gcc的编译过程
gcc编译过程详细了解细节
目录
一、gcc的编译过程
平时使用gcc,我们新手小白似乎只会使用它编译生成./a.out。
gcc hello.c
或者就是给生成的程序一个别名。
gcc hello.c -o hello
但是gcc还有很多的用处,而且了解gcc的编译过程对我们编译代码时也会提供很多帮助。
gcc编译过程有四大步骤:预处理、编译、汇编、链接
1.预处理
预处理是读取c源程序,对其中的伪指令(以#开头的指令,也就是宏)和特殊符号进行“替代”处理;经过此处理,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,仍然是C文件,但内容有所不同。
预处理的过程主要处理包括以下过程:
·将所有的#define删除,并且展开所有的宏定义
·处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等
·处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
·删除所有注释 “//”和”/* */”.
·添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
·保留所有的#pragma编译器指令,因为编译器需要使用它们
下面我们将一端简单的C代码做示例。
/* --------普通的c代码----------*/
#include<stdio.h>
#define COUNTE 5
int main(int argc,char ** argv)
{
for(int i=0;i<=COUNTE;i++)
{
printf("hello world!");
}
return 0;
}
然后经过预处理:gcc -E hello.c -o hello.i //-E只对其预处理,或者可以cpp hello.c > hello.i
其注释被删除,且宏也被替代之后删除,如上图所示。
2.编译
编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
gcc -S hello.i -o hello.s(-S将.i文件生成.s汇编文件)如下图
不同的编译器交叉编译同一个hello.i文件生成的汇编文件也不相同,这也是C语言可移植性的一种体现。
3.汇编
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。 目标文件由段组成。通常一个目标文件中至少有两个段:
·代码段(文本段):该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般不可写;
·数据段:主要存放程序中要用到的各种常量、全局变量、静态的数据。一般数据段都是可读,可写,可执行的;
gcc -c hello.s -o hello.o //-c汇编文件,不链接
4.连接
汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。 链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,也就是可执行程序。 根据开发人员指定的库函数的链接方式的不同,链接处理可分为两种:
1. 静态链接
2. 动态链接
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。
gcc hello.o -o hello -static//静态链接编译
gcc hello.o -o hello //动态链接编译
可见两种编译生成的可执行文件大小的差距,静态连接编译将静态库包含在了生成的可执行文件中,增加了其独立性,但是也使其文件大小更大。
更多推荐
所有评论(0)