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 是最好的语言!

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

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

    姚冬,中老年程序员 进藤光.杨个毛.欧阳修 等人赞同 我是来反对楼上某些答案的.我曾经用MFC写了金山词霸(大约20多万行),又用Qt写了YY语音(大约100多万行),算是对两种框架都比较有经验.纠正 ...

  2. 为什么golang的开发效率高(编译型的强类型语言、工程角度高、在开发上的高效率主要来自于后发优势,编译快、避免趁编译时间找产品妹妹搭讪,既是强类型语言又有gc,只要通过编译,非业务毛病就很少了)

    作者:阿猫链接:https://www.zhihu.com/question/21098952/answer/21813840来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出 ...

  3. 2020年使用Delphi的25个理由(我觉得四个优点:控件+可视化开发+跨平台+数据库,还有一个编译快,运行快)——人生苦短,我用Delphi!

    25年后从10个使用Delphi的理由到1个至25个使用Delphi 10.3的理由 25年前发布Delphi 1时,我汇总了使用Delphi的十大理由.这是我精通Delphi原始书的序言中的原始列表 ...

  4. iOS: FFMpeg编译和使用问题总结

    iOS: FFmpeg编译和使用问题总结 折磨了我近一周多时间的FFmpeg库编译问题终于解决了,必须得把这一段时间来遇到过的坑全写出来.如果急着解决问题,编译最新版本的FFmpeg库请直接看第二部分 ...

  5. C/C++的编译器|编译环境(非常全面的比较)

    C/C++编译器的一些易混淆概念,总结一下. 关于什么是Unix-like操作系统,常见操作系统间差异,什么是操作系统接口等等,请参考<操作系统宝鉴>. C/C++编译器有哪些? 首先是如 ...

  6. Delphi的核心优势:三快一多

    快是指:开发快(RAD开发),编译快(好像是没有用到LL(1),从而避免了潜在的歧义),运行快(原生代码). 多是指:开发符合PME标准的可视化控件,易开发,易使用,所以第三方控件特别多,这个不用解释 ...

  7. 尝试在CentOS7.2上编译安装Swift

    苹果提供 Ubuntu上构建Swift 的教程,通过这个教程我尝试使用CentOS7.2上玩儿一把.目前已经成功在CentOS7.2上班成功安装 swift 4.0 https://github.co ...

  8. iOS: FFmpeg编译和使用 学习

    ffmpeg是一个多平台多媒体处理工具,处理视频和音频的功能非常强大.目前在网上搜到的iOS上使用FFMPEG的资料都比较陈旧,而FFMPEG更新迭代比较快: 且网上的讲解不够详细,对于初次接触FFM ...

  9. 全图化引擎(AI·OS)中的编译技术

    全图化引擎又称算子执行引擎,它的介绍可以参考从HA3到AI OS -- 全图化引擎破茧之路.本文从算子化的视角介绍了编译技术在全图化引擎中的运用.主要内容有: 1. 通过脚本语言扩展通用算子上的用户订 ...

随机推荐

  1. IPv6技术详解:基本概念、应用现状、技术实践(下篇)

    本文来自微信技术架构部的原创技术分享. 1.前言 在上篇<IPv6技术详解:基本概念.应用现状.技术实践(上篇)>,我们讲解了IPV6的基本概念. 本篇将继续从以下方面展开对IPV6的讲解 ...

  2. 标签页(tab)切换的原生js,jquery和bootstrap实现

    概述 这是我在学习课程Tab选项卡切换效果时做的总结和练手. 原课程中只有原生js实现,jquery和bootstrap实现是我自己补上的. 本节内容 标签页(tab)切换的原生js实现 标签页(ta ...

  3. Javascript百学不厌 - this

    最近看了一本书,让自己的野路子走走正规路线 方法调用模式: 方法:当一个函数被保存为对象的一个属性时,我们称它为一个方法. var obj = { fun1: function() {this} // ...

  4. Shell-8--数值运算及处理

    RANDOM 默认范围是 0~32767

  5. MySQL-Cluster 和主从(Master,Slave)搭建总结

    双主互备,主从 什么是双主 MultiSource 多源复制 原理及流程图 主要步骤 1,在 Master Server 上开启 bin log 日志 和 设置 server-id  :(在my.cn ...

  6. A Nice Paper About Mobile Data Offloading

    关于Mobile Data Offloading这个研究领域的Paper基本上该有的都看过了,我想即使再有也无非是那些套路,新不到哪去.同样,这篇paper也是这样,它的出发点是改进原有的利用ad h ...

  7. 分布式作业 Elastic-Job 快速上手指南,从理论到实战一文搞定!

    Elastic-Job支持 JAVA API 和 Spring 配置两种方式配置任务,这里我们使用 JAVA API 的形式来创建一个简单的任务入门,现在都是 Spring Boot 时代了,所以不建 ...

  8. [原]Windows Azure开发之Linux虚拟机

      Windows Azure是微软的云服务集合,用来提供云在线服务所需要的操作系统与基础存储与管理的平台,是微软的云计算的核心组成组件之一.其中windows azure提供的最重要的一项服务就是虚 ...

  9. Thread-方法以及wait、notify简介

    Thread.sleep()1.静态方法是定义在Thread类中.2.Thread.sleep()方法用来暂停当前执行的线程,将CPU使用权释放给线程调度器,但不释放锁(也就是说如果有synchron ...

  10. eclipse 安装插件报错问题

    报错信息 An error occurred while installing the items session context was:(profile=epp.package.jee, phas ...