关于C与C++区别的摘录

2024-06-16 23:32
文章标签 c++ 区别 摘录

本文主要是介绍关于C与C++区别的摘录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.博主:恒虚之境

作者:恒虚之境
链接:https://www.zhihu.com/question/28834538/answer/477487776
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

大家都知道,上古时代,猿猴用机器代码写程序,而且好像还是01二进制编码的表现方式。这些01代码精确表达了计算机CPU所要做的每一个动作(每一条指令)从内存的某个地址中读数到寄存器中,寄存器中又再做那些事情,动作完了之后,又将运算结果送回内存,程序计数器跳转到那个位置,所有这些,每一个细微的动作(指令),都在01代码中体现得淋漓尽致。至于cpu怎么执行指令,可以参考《编码的奥秘》,很好的计算机硬件入门书。今时今日,最终CPU面临着的程序其实也是01的形式,只不过是猿猴语言已经跟这种形式,实在扯不上什么关系。这里旧事重提,想表达的意思是,不管猿语多高级,最终落实到CPU上执行的时候,必须还是精确无比的01代码,实实在在表达了CPU每一步的动作,半点含糊不得,没有一丝丝歧义的地方。表面上面向对象的代码,好像很智能,GC也多体贴,包括函数式程序,多么不食人间烟火的Monad,最终落实到CPU的时候,还不是要老老实实地一步一个脚印地一个不落地执行每一个细微动作。

无疑,用01写代码太无趣了。没多久,猿猴马上就改进了策略,引入助记符。也即是针对CPU上每一个指令的编号,就用英文单词或缩写来代替,至于立即数,也可以是十进制数。这也就是汇编语言了。这些汇编语言的程序代码,要执行时,先用一个简单的翻译器转换为机器代码再执行。翻译器真的很简单,不过就是通过查表法,将助记符替换为01代码,外加将十进制数字转换为二进制,翻译器用机器代码写的,因为只能用机器代码来实现。相比于原来的机器代码,翻译器实在并没有做多余的事情,意思还是那些意思,指令步骤还是那些指令步骤,一个都不能少,汇编代码与机器代码一一对应。翻译器的出现,虽然原理简单工作简单,但是减轻了猿猴记忆上的工作量,简直极大解放生产力。猿猴用汇编语言愉快地生产代码,不知道过了几多春秋寒暑。

接着就是C语言的伟大时代,面向过程,结构化编程。通过顺序执行,条件语句,循环语句,函数调用这些语法要素;又提供基本类型,数组,允许用户自定义结构体;与此同时,又保留了直接操作内存的手段,也就是指针。有了这些玩意,猿猴终于可以开始用人话与机器对话了,表达的粒度更大了。虽然相比于汇编语言与机器语言直接的一一对应,C语言与汇编语言的对应关系没那么明显,自然,这种不明显,意味着编译器要做更多的工作,也意味着一份C语言的代码,其对应的汇编语言要长了很多。但是,C语言与汇编语言,某种意义上,依然是一一对应,只不过粒度更大,以语句为单位,而不是指令。一条C语言的语句,意味着好几条汇编语言。稍加训练,猿猴马上就可以在大脑中建立这种对应关系,看到一段C语言代码,马上就可以条件反射这段代码在机器中的内存布局,以及CPU将如何执行这些C语言代码。

显然,C语言代码,某种程度上讲,具备所见即所得的特点。这种特点,说好听,就是C语言代码很清晰,很精确地表达了机器的全部动作,让猿猴有掌控一切了如指掌的虚幻快感。说句不好听就是,C语言本质上还是面向机器的语言,别看它有点像是说人话的意思。猿猴不能在其上玩稍微高级一点的动作,必须清清楚楚地写明每一步的操作,就算是重复类似的工作,如果函数没法提炼,那就没戏了。当然,可以用预处理来一定程度上减轻低抽象的痛苦。在C里面,每一个名字就代表了一个确切的意思,或者是唯一的函数或者是唯一的变量又或者是唯一的宏,不可能有那么一点智能的意思,没有函数重载没有函数重写等玩意。因此,C语言中,代码还没写多久,马上就要面临给函数起名字的纠结。

C语言编译器内部相比于简单的汇编翻译器,自然要做更多的事情。但是,它的内核还是很机械,很无趣,不做哪怕一点点多余的事情,相比于汇编语言,不过就是可以表达的粒度大了一点点,一点都不智能。不智能的意思是,它没有函数重载,没有函数重写,数据类型所蕴含的无穷潜力,在C这里仅仅用于定义内存布局,简单的类型检查。猿猴在C语言里面难以用类型玩出啥新奇的花样。代码复用的手段只有函数以及预处理,不过就是将连续操作的一段语句包装成更大粒度的东西。由于缺乏高级的抽象机制,用C语言实在没办法搞应用框架这种高大上的玩意,实在是语法很不友好,抽象粒度太细,抽象手段太单一。C语言这种语法简单内涵单薄的猿语,只有lognjmp和达夫设备还算有点点小惊喜,要精通还不是就手到擒来,再容易不过。

只有深刻感受到C语言的局限,功能残缺,才能对C++的各种改进有一点点感觉。啰里啰嗦铺垫了一大堆,好不容易终于轮到大C++粉墨登场了,只可惜本文的篇幅过长,这就打住。

表面上看,C++不过是比C多了很多语法糖,当然,每一条语法糖,都代表一种新的抽象手法,表示写优雅的代码又多了一种选择。

比如说,析构函数,用以当对象的生命周期结束时将被调用。析构函数的调用时间与函数调用的即时调用就很不一样,应该可以感受出来这种时间差异区别的明显。C语言中没有任何办法做析构函数这样延后执行的手段,除了手工显式的在作用域结束之前调用函数,就别无他法了。而大C++就大不一样,只要对象存在析构函数,只要定义对象变量,只要变量要死了,其析构函数就被调用。而且,当有多个不同类型变量聚在一起,各自都有析构函数,编译器就会很体贴的按照栈式顺序执行这些对象的析构函数,这些函数调用的动作,从代码字面上看不出来,但是C++的语义就规定了这样一系列的动作必须发生。而C语言的话,就要求猿猴明确地调用这些析构函数,而且栈式顺序也续保持一致。这么说,是否可以感受到C++编译器相对于C语言更智能一些了。C语言的所见即所得的意思,就是一切要做的事情,猿猴必须给我一一写出来,否则,本编译器绝不多做一点点多余的事情。重复自动化的明确工作,机器来做远比人类可靠,因为机器是不会错的。就拿析构函数调用这件事情来说,猿猴可能就漏了调用代码,又或者调用顺序就错了。

又比如说,虚函数,虚函数表,就可以将多个不同的函数打包在一起,这样子,在模板方法中的几个关键点上,同样的虚函数名称调用下,子类就各自做不同的动作系列。当然,虚函数不仅仅用于模板方法。虚函数相比于函数调用,又是全新的抽象手段。对于面向对象语言来说很自然的语法,C语法要费老大劲才能达到同样的效果,定义虚函数表结构,创建虚函数表变量,初始化虚函数表内容,每次创建对象时,设置正确的虚函数表指针。然后,调用虚函数时,还要通过索引找到虚函数指针,再将对象地址还有其他参数传递给虚函数。鉴于虚函数的使用,对于C语言来说,这么麻烦,猿猴一般都不会在代码中轻易使用。猿猴每次使用虚函数,C++编译器就暗地里要做这么多的事情。而程序字面上,代码上的虚函数调用也不再能够明确指明其调用的具体是哪一个函数。

C++的构造函数、函数重载、操作符重载、隐式类型转换、异常等等,那个不是为了让编译器多做一点事情,自动化产生代码。如果你承认机器的自动化生产代码就是好,就是妙,更何况这种自动化生产代码行为,全在猿猴的掌控之中。那应该可以欣然接受C++要比C不要好太多的结论。但是,具体到代码的二进制复用以及内存布局上,却一塌糊涂,特别是多继承,孰优孰劣,有点不好取舍了。

如果仅仅是这样,那也没什么,相比于C,C++只是多了一些语法糖,多了一些抽象手段,在输出优雅代码时多了一些更好的选择,而且由于C++的自由随意,这些语法糖可以随心所欲组合,搞出来很多花样,但是充其量,还是停留在与CPU对话的猿语层面。就算只是这样,其实已经有很多猿猴开始跟随不上C++的脚步了,很多猿猴,就算是class这个概念,也玩不好。可是后来,C++搞出了template这个关键字,而且还图灵完备。而template又可以横跨切入到面向对象(多继承),预处理,内存操作,全局对象等,这些家伙,本来每一个都不是省油的灯,就给人带来了很大的困惑。这种困惑,虽然反映到代码上的理解比较吃力,但是,更麻烦的是,猿猴摸不准template对整个语言抽象度的提升究竟作用有多大,而答案是,这种提升非常大,以至于C++的代码表达能力,几乎无所不能。(待续)

2.博主:马遥

误区3:C是C++的子集,C支持的语法C++都支持。不对。

C++在最初设计时是基于C的,绝大多数语法都兼容。但是,在一些细节却重要的地方,二者差别非常大。

例如,C语言的函数指针非常神奇:

int (*pfunc)();

看上去pfunc可以指向返回值为int,无参数的函数?并不是。

实际上pfunc可以指向任意返回值为int的函数,无论参数是什么。

而无参的情况必须写明参数为void:

int (*pfunc)(void);

C语言不必指定参数类型也可以引用函数,这一点让C语言具有很强的动态特性。而C++去除了这种设计,因为破坏了类型安全。

同理,C语言常用的(void*)转换在C++中也在很大程度上摒弃了,理由也是类型不安全。

3.博主:坐下坐下基本操作

C 面向机器编程
Cpp 面向编译器编程

面向编译器编程实在太有意思了

这篇关于关于C与C++区别的摘录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067857

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

读书摘录《控糖革命》

又到了每周推荐时间,这周末给大家推荐一本书《控糖革命》。身体是革命的本钱,只有保持健康的身体,才能保证持久的生产力,希望我的读者都可以身体健康,青春永驻。 推荐前,首先申明在《控糖革命》一书中,作者提出了一些颇具争议的观点,这些观点并没有经过系统的科学论证,但这并不妨碍我们从中获取一些有益的控糖建议。作者通过分享作者的个人经验和研究,为我们提供了一种全新的饮食理念,帮助我们更好地控制血糖峰值

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现