关于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++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

售价599元起! 华为路由器X1/Pro发布 配置与区别一览

《售价599元起!华为路由器X1/Pro发布配置与区别一览》华为路由器X1/Pro发布,有朋友留言问华为路由X1和X1Pro怎么选择,关于这个问题,本期图文将对这二款路由器做了期参数对比,大家看... 华为路由 X1 系列已经正式发布并开启预售,将在 4 月 25 日 10:08 正式开售,两款产品分别为华

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序