下面我们来了解一下用GCC编译器编译C可执行脚本的过程。gcc是一个超级编译器,可以在多种硬件平台上编译可执行程序,其执行效率平均比普通编译器高20%到30%。gcc编译器可以将C、C++语言源程序、汇编程序、目标程序编译链接成可执行文件。如果没有给出可执行文件的名称,gcc将生成一个名为a.out的文件。在Linux系统中,可执行文件没有统一的后缀,系统根据文件属性来区分可执行文件和不可执行文件。而gcc使用后缀来区分输入文件的类型。下面介绍一下gcc遵循的一些约定规则。后缀为.c的文件为C语言源代码文件;后缀为.a的文件是由目标文件组成的归档文件;后缀为.C、.cc或.cxx的文件为C++源代码文件;.后缀为h的文件是程序包含的头文件;后缀为.i的文件为预处理后的C源代码文件;后缀为.ii的文件为预处理后的C++源代码文件;后缀为.m的文件为Objective-C源代码文件;后缀为.o的文件为编译后的目标文件;后缀为.s的文件为汇编语言源代码文件;虽然gcc的执行过程称为gcc是C语言编译器,但是使用gcc将C语言源代码文件生成可执行文件的过程不仅仅是一个编译过程,而是四个相互关联的步骤:预处理(也叫预编译),预处理),编译,汇编和链接。gcc命令首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)和预编译语句(如宏定义define等)进行分析。然后调用cc1编译。该阶段根据输入文件生成后缀为.o的目标文件。汇编过程是针对汇编语言的步骤、调用而工作的,一般来说,汇编语言源代码文件和后缀为.s的汇编文件,以及后缀为.s的汇编语言文件。带有后缀的目标文件。当所有目标文件生成后,gcc调用ld来完成最后的关键工作,即链接。在链接阶段,所有的目标文件都被安排在可执行程序中的适当位置,同时程序调用的库函数也从各自的档案中链接到适当的位置。1.预处理(生成预编译文件,.i文件)gcc–Ehello.c–ohello.i//必须加上.c后缀,这样gcc才能识别预处理过程,主要处理那些以#开头的预处理文件源码编译说明,主要处理规则如下:①删除所有#define,展开所有宏定义;②处理所有条件编译指令,如#if、#ifdef等;③处理#include预编译指令,将include文件插入到该预编译指令所在位置。该过程递归进行,包含的文件还可能包含其他文件。④删除所有注释//和/**/;⑤添加行号和文件标识符,如#2"hello.c"2,使编译器生成行号信息,方便调试,编译时生成行号信息,在编译错误或警告时可以显示行号信息;⑥保留所有#pragma编译器指令,因为编译器需要使用它们;2.编译(生成预编译文件,.s文件)gcc–Shello.i–ohello.s//不用指定名字,默认生成.s文件。编译过程就是对预处理后的文件进行一系列的词法分析、句法分析、语义分析和优化,生成相应的汇编代码文件。3.Assembly(生成汇编代码,.o文件)gcc–chello.s–ohello.o//可以不指定,默认生成.o文件。汇编器就是将汇编代码转换成机器可以执行的命令。一条汇编语句几乎对应一条机器指令。4、链接(生成可执行文件)gcchello.o–ohello链接器ld将各种目标文件组装在一起,解析符号依赖、库依赖,生成可执行文件。假设我们有一个名为hello.c的C语言源代码文件,最简单的生成可执行文件的方法是:gcchello.c-omyhello//一步就可以完成此时,预编译和编译一次连接完成后,会生成一个名为myhello.out的系统预设可执行文件。
