典型的 C++ 编译过程分 “预处理” “编译” “链接”
编译, 是最耗时的环节, 编译需要编译器解析 C++ 语法, 构建 AST (抽象语法树), 解析完成后, C++ 的重任才刚刚开始. 对于 C 来说, C 解析成语法树后可以立即开始生成目标代码. 但是 C++ 不能. 最耗时的步骤才刚刚开始. C++ 要在 AST 上执行 模板展开, 重载判决. 特别是 模板展开, 这可是一次图灵完全的展开啊! 在展开的过程中, 顺便就以图灵完全的模式执行了一次模板代码. 模板展开失败不是错误, 编译器需要找到另外的模板重载重新展开.
终于全部任务执行完毕后, 生成一个中间的表示. 接着开始进行第一阶段优化, 这一阶段的优化, 死代码消除, 内联展开. 这很重要, 模板代码就是在这一阶段被内联进去, 以至于和手写一样高效. 死代码消除使得为可读性考虑写的代码, 并不会真正生成目标代码, 编译器知道这是无用, 删了. 完成第一阶段优化后, 转化为目标代码. 转换完成后执行第二次优化. 这次优化是在机器指令层面进行的. 优化的地方有, 向量化啦, 指令重排序啦.
最终生成优化的目标代码, 然后写入目标文件, 等待链接.
其中, 预处理+解析语法树, 这两个过程, 在很多时候, 都是非常非常非常费时的操作. 虽然从语法树生成目标代码也非常耗时,但是如果不开启编译优化, 这个过程还是非常迅速的.
不论开关优化, 预处理+解析语法树的时间, 是省不了的.
对程序员来说, 代码是靠编辑器写出来的. 那么, 编辑器的强大能极大的加速程序员的生产效率.
什么叫强大的编辑器? 最最最重要的一点: 智能提示.
智能提示的核心,就是语法解析器。 并将解析到的语法,存储在数据库里。你修改一行代码, 编辑器不会像 C++ 编译器那样重新解析整个文件, 而是只重新解析 修改的那部分。以为其他没有修改的部分的语法,已经在数据库里了呀!
等等!也就是说,其实 IDE 已经将程序的所有语法都掌握在手里了, 不像编译器一次只能看到一个文件, 编辑器可是看到了全部的文件!
而且, 有改动,编辑器也知道到底哪里改了!编辑器不会像 C++ 编译器那样重新解析整个文件, 而是只重新解析 修改的那部分。 如果编辑器随时把自己存储的所有语法树的信息,给转化为二进制代码呢?
这不就成了即时编译了!!!!!!
而且, 和项目的大小无关,只和改动集的大小有关!
这真是太好了,所有的编译都在完成编辑的时候完成了!
Comments