编译器

  绝大部分摘自《程序员的自我修养》一书,侵删。

  对于平常的的开发,我们很少关注到编译和链接的过程,因为我们通常在IDE中进行开发,而IDE会把编译和链接合在一起一步完成,称为构建(build),就算我们使用命令行编译,也只用一行代码就能够完成非常复杂的过程,g++ hello.cpp 就能生成一个可供执行的exe文件。

  而在平时的开发中,IDE提供的默认配置和强大功能掩盖了系统软件的运行机制,偶尔程序出现的莫名其妙的错误,我也只能被水淹没,不知所措。学一波编译器,希望能解决掉我exe运行不了的问题。。。

 

  从源文件到可执行文件的操作分为四步:

    1.预编译    (.c/.cpp--->.i/.ii)

    2.编译     (.i/.ii--->.s)

    3.汇编     (.s--->.o)

    4.链接     (.o--->.out)

 

  1.预编译

    .c和.cpp或.cxx被预编译后分别会生成.i或.ii文件,相当于:

      gcc -E hello.c -o hello.i

    或者

      gcc hello.c>hello.i

    在c语言中存在许多以#开头的语句,这些语句叫做预编译指令,例如: #include #define #if 等,而预编译的作用就是将这些内容全部处理掉:

                 1. 删除所有的#define 并将宏定义展开

      2. 处理所有的条件预编译指令,如#if #ifdef #eif #else #endif

      3. 处理#include ,将被包含文件插入改预编译指令的位置。这个过程递归进行,也就是说被包含文件还可能包含其他文件

      4. 删除所有注释

      5. 添加行号和文件名标识比如#2 "hello.c" 2 以便于编译器产生调试用的行号信息,编译产生错误时能显示行号 

      6.保留所有的#pragma 编译器指令

    我们可以通过查看预编译后的i文件来判断宏定义和头文件是否正确。

  2.编译和汇编

    编译器负责将你的高级语言转换为汇编语言,对预处理后的i文件进行词法分析、语法分析、语义分析、优化后生成汇编文件。

    编译器会将表达式由扫描器(scanner)转化为记号,再由语法分析器(Grammar Parser)转换为语法树(Syntax Tree)(运算符的优先级就在这里体现出来,优先级越高所在层数越大,常量或变量的标识符在最深一层),接着由源码级优化器(Source Code Optimizer)在源代码级别进行优化,产生中间代码(Intermediate Code),再由代码生成器(Code Generator)目标代码优化器(Target Code Optimizer)产生汇编代码并进行优化并寻址,生成最后的目标文件,也就是一行行的汇编代码。

 

 

    

posted @ 2016-12-10 11:10  TychusLee  阅读(268)  评论(0编辑  收藏  举报