为什么 C# 比 C++ 编译快那么多

Go 我不懂,下面以 C++ 和 C# 对比来说明为什么 C++ 编译慢和 C# 编译快。

C 和 C++ 文件的编译经过几个主要步骤:

  1. 处理续行符处理(“\”)之类的杂事
  2. 词法分析,解析出 tokens 来
  3. 预处理,宏展开,处理 #include ,然后对 #include 包含的文件又重复 1~3 步骤。
  4. 重新词法分析
  5. 语法分析生成抽象语法树 AST
  6. 语义分析
  7. 优化生成代码

C# 的步骤:

  1. 处理续行符处理(“\”)之类的杂事
  2. 词法分析,解析出 tokens 来
  3. 语法分析生成抽象语法树 AST
  4. 语义分析
  5. 优化生成代码

首先,直观的看,从编译阶段上来说 C# 就比 C++ 少,这是一个原因。

另一个原因是语言的编译速度跟语法关系很大,高级语言编译一般是经过词法分析=>语法分析=>语义分析=>优化生成代码几步,如果语言的语法上没有歧义,编译的每个阶段都是独立的,那么编译速度自然就快。

如果不是这样,语法上有歧义,比如 C++ 嵌套模板的">>"和位操作的“>>”,当编译器遇到嵌模板">>"的时候只有先放着,然后往前多看几步才能确定到底是模板的尖括号还是移位,自然比没有语法歧义的语言要慢啦。

再举个例子,C++调用模板函数实例化时可以省略<>让编译器自己去推导最合适的重载,C# 泛型方法调用也可以省略 <>。类似这样的语法元素使得编译器在语法分析阶段就不能够确定一个函数调用是否是函数模板实例化(对于 C# 来说是泛型方法调用)还是一个普通的函数调用,而要等到语义分析阶段才能确定,所以在这一点上 C++ 和 C# 其实都选择牺牲编译速度来为人类减少击键次数做贡献并略微提高了代码的可读性。

还有一个方面是C和C++的编译时代码生成问题产生的:头文件和宏定义会在编译时生成代码,宏展开和引入头文件相当于硬插入了一大段文本,让编译器需要重新从词法分析开始分析,模板什么的虽然不是直接插入文本,但处理起来也很麻烦,消耗了不少的编译时间。如果 C/C++ 不是用头文件而是某种形式的编译模块,多个源文件(编译单元)引用同一个模块那么编译器只需分析一次该模块生成 AST 反复使用,那编译速度也能提升不少。

比起 C/C++ 笨笨的文本插入形式的 #include,C# 编译器完全省去了头文件的编译,你引用的 assembly 直接提供了类型和方法神马的元数据,编译器直接拿来用就好。

最后,因为 C# 没有宏和模板之类的代码生成手段,泛型也是运行时处理的,进一步加快了编译速度。

----------
题外话
关于编译器自举跟编译速度关系不大,目前(VS2013)的 C# 编译器应该是 C++ 写的,编译速度很快,但是 Mono 的编译器是 C# 写的,感觉并不慢,至少没有数量级上的差异。现在连 M$ 新的 C# 编译器 Rosylin 也完全用 C# 写了,还很模块化,性能也不差哦。

说了这么多,其实我的意思是 C++ 和 C# 比 PHP 的编译速度差远了,PHP 是最好的语言!

时间: 2024-12-17 16:30:20

为什么 C# 比 C++ 编译快那么多的相关文章

让QT编译快一点(增加基础头文件)

姚冬,中老年程序员 进藤光.杨个毛.欧阳修 等人赞同 我是来反对楼上某些答案的.我曾经用MFC写了金山词霸(大约20多万行),又用Qt写了YY语音(大约100多万行),算是对两种框架都比较有经验.纠正几个错误的认识. 1. “用Qt写的程序编译比MFC慢”的说法是错误的绝对错误,单位代码行数编译Qt远比MFC快得多,因为Qt库的头文件设计非常好,尽量都使用了前置声明,避免了头文件嵌套,几乎所有类都使用了公有类和私有类的设计,把没必要公开的声明放到私有头文件里,避免了编译时引入过多代码.而MFC没

iOS: FFmpeg编译和使用 学习

ffmpeg是一个多平台多媒体处理工具,处理视频和音频的功能非常强大.目前在网上搜到的iOS上使用FFMPEG的资料都比较陈旧,而FFMPEG更新迭代比较快: 且网上的讲解不够详细,对于初次接触FFMPEG的新手(例如我)来说确实不太好使用.为了防止忘记,这里对iOS下使用FFMPEG做一个总结. 1. FFMPEG层次结构的简单理解 要使用FFMPEG,首先需要理解FFMPEG的代码结构.根据志哥的提示,ffmpeg的代码是包括两部分的,一部分是library,一部分是tool.api都是在l

gcc 动态编译 动态库路径

gcc 动态编译(共享库) 动态编译的可执行文件需要附带一个的动态链接库,在执行时,需要调用其对应动态链接库中的命令优点:体积小,编译快缺点:依赖性高 代码如下: [[email protected] shared]# cat add.cint add (int x, int y) {return x + y;} Parsed in 0.007 seconds at 12.13 KB/sadd.c 求和函数 代码如下: [[email protected] shared]# cat print.

3.23linux内核编译学习

写了一个小时,结果图书馆网不好,结果没保存,嘤嘤嘤,来重新返工了. 昨天的操作系统第一个实验,编译linux内核,看成实验教程做比较简单,过程也比较顺利.但还有一些小问题.老师要求用Ubuntu14.10,开始自己在极速上随便下个 Ubuntu GNOME 15.10,装起来蛮快的,进系统之后美瞎了,但是怕后续实验出错,就没敢在这个上面编译,哎是个遗憾.后来直接用的之前装Tinyos的ubuntu,内核版本是linux 3.19.1,没用更新的内核版本试下,又是个遗憾. 第一步,解压,因为直接用

Xcode编译ffmpeg(2)

iOS: FFmpeg编译和使用问题总结 折磨了我近一周多时间的FFmpeg库编译问题终于解决了,必须得把这一段时间来遇到过的坑全写出来.如果急着解决问题,编译最新版本的FFmpeg库请直接看第二部分,编译较老版本(0.7)的FFmpeg库请直接跳至第七部分,那里有你想要的编译脚本,但别忘了抽空看看全文. 一.背景 网上有很多FFmpeg编译配置的资料,大部分都是关于FFmpeg最新的版本(2.0)的,我一开始也想着编写一个2.0版本的,可以放到接手的那个项目中,发现各种问题(无法快进,没有声音

iOS: FFmpeg编译和使用问题总结 ( 一 )

一片枫叶 追求卓越,成功就会在不经意间追上你 跟随自己的节奏学习,思考,总结,找到自己,别人才会找到你 下一篇:基于NSBundle的工程结构 iOS: FFMpeg编译和使用问题总结 iOS: FFmpeg编译和使用问题总结 折磨了我近一周多时间的FFmpeg库编译问题终于解决了,必须得把这一段时间来遇到过的坑全写出来.如果急着解决问题,编译最新版本的FFmpeg库请直接看第二部分,编译较老版本(0.7)的FFmpeg库请直接跳至第七部分,那里有你想要的编译脚本,但别忘了抽空看看全文. 一.背

AndroidStudio用法总结

环境搭建: 有as安装版本和绿色版本:下载:http://androiddevtools.cn ps:如果你从eclipse转as开发工具上,建议用as安装版本.因为考虑到 as时刻升级要求默认升级sdk,避免相互干扰,导致ADT插件匹配不上: gradle配置安装后,设置相应的path 现教程为as1.2版本安装版本: 配置环境: 安装时可能碰到的情况: 第一次安装后启动后可以会出现一直在加载的界面: 这是在检查你的 Android SDK .有人会在这里卡上很长时间,很大的原因就是:网络连接

JS正则表达式完整教程(略长)

JS正则表达式完整教程(略长) 引言 亲爱的读者朋友,如果你点开了这篇文章,说明你对正则很感兴趣. 想必你也了解正则的重要性,在我看来正则表达式是衡量程序员水平的一个侧面标准. 关于正则表达式的教程,网上也有很多,相信你也看了一些. 与之不同的是,本文的目的是希望所有认真读完的童鞋们,都有实质性的提高. 本文内容共有七章,用JavaScript语言完整地讨论了正则表达式的方方面面. 如果觉得文章某块儿没有说明白清楚,欢迎留言,能力范围之内,老姚必做详细解答. 具体章节如下: 引言 第一章 正则表

Android Studio 2.2 来啦

今年的 I/O 2016 Google 放出了 Android Studio 2.2 的预览版,透露改进了多项功能,只不过为了保证公司项目不受影响,我一般都不安装预览版的,因为预览版意味着不稳定,可能遇到各种意想不到的坑,昨天,Google 终于发布了 Android Studio 2.2 的正式版,于是赶紧第一时间体验了下,按照 Google 的说法本次更新包含了三个方面:speed, smarts, and Android platform support,言外之意就是更快.更智能,而且增加