现如今我们使用的无论是C语言、C++或者是Java等 编程语言都是高级语言,其出现的主要目的是为了方便编程人员进行程序的编写,而这些指令越来越趋近于人类日常使用的语言,我们的计算机是识别不出来的,就像是一个中国作家写了一本书,如果一般的外国人想要读的话,那就必须有人翻译出译本才行。计算机也是同样,而这时我们的编译器便充当了翻译的使者。即编译器是将上层高级语言代码就是成为对应平台的cpu指令,能够被cpu识别执行。
编译的过程
在学习编译器工作之前,我们首先要知道正常的一个程序文件在编译时需要经历的各项过程。
1. 预处理阶段
预处理阶段是展开所有的代码,进行例如引入头文件、宏替换、删除注释、文件包含、条件编译等功能,在这一步将生成后缀为 .i 的文件。并且经过预处理得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字等。不对代码的正确性进行检查。
2. 编译阶段
编译阶段主要对代码的规范性进行检查,检查是否有词法错误和语法错误,若产生错误则进行报错处理,若正确则生成后缀为***.s***的汇编代码文件。
3. 汇编阶段
汇编阶段主要将编译阶段产生的 .s 文件转化成目标文件,即将汇编代码转化成后缀为 .o 的二进制目标代码。二进制目标文件主要由代码段和数据段两个部分组成,对于代码段,其中包含的是程序的指令,仅可读可执行但是不可写;对于数据段,主要保存的是程序中要用到的全局变量与静态的数据,其具有可读、可写、可执行的全部权限。
4. 链接阶段
仅仅将文件转化成机器可识别的二进制目标文件还远远不够,整个程序并不能正常的运行,那是因为有些程序的地方可能调用了其他库或者其他文件当中的内容,这时便需要通过链接将各个文件或者用到的库建立关系。链接阶段的主要工作就是将有关的目标文件彼此联系,形成一个可以共同合作运作的整体。
在这里,根据链接方式的不同,一般可分为以下两种链接方式,分别是静态链接与动态链接。
静态链接
静态链接,工作方式正如其名一般不进行花里胡哨的动态行为,在链接的时候,将该程序中所用到的各种特殊符号或者库函数直接从源文件中拷贝到当前代码中,这样在执行时便可以自给自足,不用再向其他地方借函数。其优点在于当代码进行移植时,就算没有库函数依然可以正常运行,但是缺点也正如我们所看到的那样,重复相同的代码过多,造成冗余。其后缀名一般为***.a***。
动态链接
动态链接,与静态链接恰恰相反,喜欢进口操作,已经有的或者可以借到的函数等绝不自己写,反而仅仅只记录共享对象的名字以及少量的登记信息。其优点在于代码简洁,缺点在于容易出问题,倘若库函数丢失,那么程序便无法正常运行。其后缀名一般为***.so***。
gcc工具
gcc工具是C语言编译器,记住如下选项以及使用格式,即可对一个正常的程序进行编译运行。
常用选项及使用格式
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S 编译到汇编语言不进行汇编和链接
-c 编译到目标代码
-o 文件输出到 文件
-static 此选项对生成的文件采用静态链接
-g 生成调试信息。GNU 调试器可利用该信息。
-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
-O0
-O1
-O2
-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
例:
如下一个code.c文件
第一步:预处理阶段
gcc -E code.c -o code.i 将code.c文件进行预处理生成code.i文件
【注意】可见现在源文件变成了38行在源文件的基础上进行了扩展。
第二步:编译阶段
gcc -S code.i -o code.s 将code.i文件进行编译产生code.s文件
第三步:汇编阶段
gcc -c code.s -o code.o 将编译完成的文件经汇编生成目标文件***.o***为后缀。
第四步:链接阶段
gcc code.o -o code.exe 进行链接直接生成可运行文件。
【注意】以上步骤是将各各过程逐一显示,在实际中可以直接使用 gcc code.c -o code.exe
指令