C语言程序代码编译成可执行文件的过程

C语言程序代码编译成可执行文件的过程

1.1 预处理阶段

由预处理器完成, 生成的文件后缀名为 .i。这是一种标识,表明这些文件是经过预处理的中间代码文件。如果原始的C语言文件名是example.c,那么经过预处理后生成的中间代码文件名可能是example.i。它仍然是一个文本文件, 其中的内容是可读的C语言代码

  1. 宏替换: 预处理器会识别源代码中的宏定义,并将宏名称替换为其相应的定义。宏替换会根据预处理指令中的参数来生成新的代码。例如,对于以下代码:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int result = MAX(10, 20);

预处理器会将所有的MAX(10, 20) 文本替换为 ((10) > (20) ? (10) : (20))

  1. 文件包含: 预处理器会处理源文件中的#include指令,将指定的文件内容插入到当前文件中。这样,可以将多个源文件组合在一起,形成一个大的源文件。

  2. 条件编译: 预处理器能够根据条件编译指令(如#ifdef#ifndef#if等)来选择性地包含或排除部分代码块。这对于根据不同的编译条件来选择性地编译代码非常有用。

  3. 删除注释: 预处理器会删除源代码中的注释,这些注释在预处理阶段后将不再存在于编译后的代码中。

  4. 处理特殊符号: 预处理器会处理一些特殊的预处理指令,如#pragma,它可以用来向编译器传递特定的指令或标记。

  5. 行号标记: 预处理器会在代码中插入行号和文件名信息,这对于编译错误的定位和调试非常有用。

1.2 编译阶段

由编译器完成, 生成的是汇编语言文件, 后缀名为.S的, 它文本文件 , 其中的内容是由汇编指令组成的汇编代码

  1. 词法分析(Lexical Analysis): 编译器首先对预处理阶段生成的代码进行词法分析,将源代码划分为一系列的词法单元(Tokens)。词法单元包括关键字、标识符、运算符、常量等。
  2. 语法分析(Syntax Analysis): 语法分析阶段将词法单元转化为语法树(Syntax Tree)或抽象语法树(Abstract Syntax Tree,AST),用于表示源代码的语法结构。这个阶段会检查代码是否符合C语言的语法规则。
  3. 语义分析(Semantic Analysis): 语义分析阶段会对语法树或AST进行更深层次的分析,检查标识符的声明和使用是否一致,以及类型的匹配等语义问题。编译器会生成符号表,记录变量、函数和类型等信息。
  4. 生成中间代码(Intermediate Code Generation): 在生成中间代码阶段,编译器将语法树或AST转化为中间代码表示,这是一个抽象的表示,不直接对应于特定的机器指令集,但可以更容易地进行优化和转换。
  5. 优化(Optimization): 中间代码生成后,编译器可能会进行代码优化,以提高程序的性能和效率。优化包括诸如消除冗余计算、减少存储访问等技术。
  6. 生成汇编代码(Assembly Code Generation): 最终,编译器会将中间代码转化为目标机器的汇编语言代码。这些汇编代码是与特定硬件架构相关的,可以由汇编器将其转化为机器码。

编译阶段的最终目标是生成汇编代码,这些汇编代码可以由汇编器和链接器进一步处理,最终生成可执行的二进制文件。编译阶段主要负责将高级的C语言代码转化为中间表示,以便后续的优化和转换,以及生成适用于目标硬件的汇编代码。

1.3 汇编阶段

由汇编器完成, 将上一步生成汇编文件进行汇编, 将汇编指令汇编成机器指令, 生成目标文件, 后缀名为.o 这是二进制文件, 其中的内容是难以被人们读懂的机器码

  1. 符号解析(Symbol Resolution): 编译器会解析各个目标文件中的全局符号(变量、函数名等),并将这些符号进行匹配和关联。如果多个目标文件中有相同的符号名,链接器会负责解决这些符号的重复定义问题。
  2. 重定位(Relocation): 由于不同的目标文件可能在内存中的不同位置加载,链接器会对生成的机器码进行重定位操作,以确保所有代码和数据都正确地映射到内存中的适当位置。
  3. 库文件链接(Library Linking): 如果代码中使用了外部库函数,链接器会在标准库或自定义库中查找这些函数的实现,并将其与程序的其他部分进行链接。
  4. 生成可执行文件: 在符号解析和重定位完成后,链接器会将所有目标文件及库文件组合在一起,生成最终的可执行文件。这个可执行文件可以在操作系统上运行,执行程序的功能。
  5. 符号表更新: 链接器会生成一个新的符号表,其中包含了最终可执行文件中的所有符号的地址和偏移信息。这个符号表对于调试和动态链接非常重要。
1.4 链接阶段

由链接器完成, 链接阶段的最终目标是生成一个完整的、可在操作系统上运行的可执行文件。可执行文件是一个二进制文件, 在windows上面, 可执行文件的后缀名通常是.exe , 而在Unix和类Unix操作系统中, 可执行文件通常不会去设置后缀名.

  1. 可执行文件:
    链接器会将所有的目标文件(.o 文件)以及可能的库文件(如动态链接库 .so 或静态链接库 .a 文件)合并在一起,生成一个完整的可执行文件。这个可执行文件包含了程序的所有代码和数据。

  2. 符号表:
    可执行文件中会包含一个符号表,其中记录了各个函数、变量等符号的地址、偏移量等信息。这个符号表在程序运行时用于调试和动态链接等。

  3. 重定位表:
    由于不同目标文件可能在内存中的不同位置加载,可执行文件会包含一个重定位表,记录了需要在运行时进行的重定位操作。这些操作将确保代码和数据正确地映射到内存中的适当位置。

  4. 其他元数据:
    可执行文件还可能包含其他的元数据,如程序入口点、程序头部信息等。这些信息对操作系统加载和运行程序都非常重要。

链接的意义: c语言文件通过#include的方式将依赖文件包含进来, 但是#include包含进来的都是头文件, 这些头文件只是标识符以及函数的定义, 并没有实现, 所以链接器需要将依赖相关的实现链接起来, 才能生成一个可以执行的文件

  • 12
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值