C语言编译过程

概述

我们写出的C语言代码(.c文件),若要在机器上运行,需要经过一个编译过程,主要分为如下四个阶段(参考1,表1):

  • 预处理阶段,即完成宏定义和include 文件展开等工作;生成.i文件。GCC命令为:·gcc -E
  • 根据编译参数进行不同程序的优化,编译成汇编代码;生成.s文件。GCC命令为:·gcc -S
  • 用汇编器把上一阶段生成的汇编代码进一步生成目标代码;生成.o文件。GCC命令为:·gcc -C
  • 用链接器把上一阶段生成的目标代码、其他一些相关的系统提供的目标代码(如crtx.o)和系统或用户提供的库链接起来,生成最终的执行代码。生成可执行文件。GCC命令为:·gcc

具体如下所示(参考2)

预处理(Preprocessing)

预处理主要进行以下几个方面的处理:

  1. 宏定义指令
    #define Pi 3.1415,预处理阶段会将程序中所有的Pi用3.1415代替。与之对应的#undef 则会取消对某个宏的定义,使之后面出现时不再被替换。
  2. 条件编译指令
    #ifdef#ifndef#else#elif#endif等伪指令的引入可以使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理,即预处理阶段将根据有关的文件将不必要的代码过滤掉。
  3. 头文件包含指令
    #include,头文件中一般通过#define定义了一些宏(如字符常量),同时也包含了各种外部符号的声明。采用头文件可以使一些定义在多个不同的C源程序中使用,而不必在文件中重新定义。预处理阶段会将头文件中的定义加入到引用它的代码中。
  4. 特殊符号
    如在源程序中出现的FUNCTION会被解释为当前被编译的C源程序中的函数名称。预处理阶段会对源程序中出现的这些特殊符号用合适的值进行替换。

总结:可以看出,预处理阶段主要是完成对源程序的替换工作。经过替换后,会生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件.i,该输出文件中只有常量如数字、字符等,或者是变量的定义,以及C语言的关键字如ifelse等。

编译(Compilation)

编译阶段所有做的工作就是通过词法分析和语法分析,在确认所有指令都符合语法规则之后,将其翻译成等价的中间代码或者是汇编代码。

编译阶段会对代码进行优化处理,不仅涉及到编译技术本身,还涉及到机器的硬件环境。优化分为两部分:

  • 不依赖于具体计算机的优化。主要是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制、已知量的合并等)、无用赋值的删除等
  • 同机器硬件结构相关的优化。主要考虑如何充分利用机器的硬件寄存器存放的有关变量的值以减少内存的访问次数;根据机器硬件执行指令的特点对指令进行调整使目标代码比较短,执行效率更高等。

汇编(Assemble)

汇编是把汇编语言代码翻译成目标机器指令的过程。目标文件中存放的是与源程序等效的目标机器语言代码。目标文件由段组成,通常一个目标文件中至少有两个段:

  • 代码段:主要包含程序的指令。该段一般是可读和可执行的,一般不可写。
  • 数据段:主要存放程序中用到的各种全局变量和静态的数据。一般数据段是可读、可写、可执行的。

链接(Linking)

链接阶段的主要工作是将有关的目标文件相链接,即将一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有这些目标文件成为一个能够被操作系统执行的统一整体。举例如下:

某个源文件的函数引用了另一个源文件中定义的变量和函数,因此需要链接阶段将这些变量和函数连接在一起。

根据开发人员指定的同库函数的链接方式的不同,链接处理分为两种:

  • 静态链接:
    函数代码将从其所在的静态链接库中被拷贝到最终的可执行程序中。
  • 动态链接:
    此时,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所做的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的信息,在可执行程序被执行时,动态链接库的全部内容将被影射到运行时相应进程的虚拟地址空间。动态链接程序将根据可执行程序中记录的信息找到对应的函数代码。

备注:使用动态链接能使最终的可执行文件较小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。

附录

表1 GCC识别的主要文件扩展名

文件扩展名 文件类型
.c C语言代码
.C、.cc C++语言代码
.i 预处理后的C语言代码
.s、.S 汇编语言代码
.o 目标代码
.a 静态链接库(程序编译时使用)
.so 动态链接库(程序运行时使用)

参考

  1. ARM嵌入式Linux系统构建与驱动开发范例,周立功,P16
  2. C语言的编译链接过程详解
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 示例代码 a.c head.h head.c 预处理 处理关于 “#” 的指令 删除#define,展开所有宏定义...
    第八区阅读 471评论 0 0
  • 写在前面 对于C语言,我们大家可能不陌生。工作中经常会使用到,我们在工作中写代码,其中的编译和执行过程都是交给ID...
    Vector_Wings阅读 845评论 0 1
  • 我们一般使用命令: gcc main.c 把main.c生成可执行文件a.out gcc helloWorld.c...
    小花来了阅读 704评论 0 0
  • 1,编译预处理(gcc -E main.c -o main.i) 文件包含复制 将源文件中一"#include"格...
    ytlm阅读 268评论 0 1
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,774评论 0 27