GCC编译C:C++的四个过程

从源码到可执行程序,经历四个过程: 预处理、编译、汇编和链接,前三步由使用编译器来完成、链接由链接来完成。

  • 编译器将编译工作主要分为预处理,编译和汇编三部
  • 连接器的工作是把各个独立的模块链接为可执行程序
  • 静态链接在编译期完成,动态链接在运行期完成

阶段名 生成文件类型 预处理(

) 生成

文件 编译(

) 生成

文件 汇编(

) 生层

文件 连接(

) 生成

文件

gcc 选项

选项 含义

查看编译器的版本,像是 gcc 执行时的详细过程

输出名为

的文件,这个不能与源文件名称相同

只预处理,不会编译、汇编、链接

只编译,不会汇编、链接

只编译和汇编,不会连接

在编译过程中,除非使用了-E、-S、-C选项(或者编译出错阻止了完整的编译过程),否则最后的步骤都是链接

文件类型

编译器支持许多和C语言程序相关的扩展名,对它们的说明如下:

扩展名 说明 后期操作 命令

程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编 gcc -E test.c -o test.i

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C++程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

程序源代码,在编译之前要先进行预处理。 预处理、编译、汇编

C程序预处理输出,可以被编译。可以理解为预处理翻译(

)后的文件 编译、汇编 gcc -s test.i -o test.s

C++程序预处理输出,可以被编译。可以理解为预处理翻译(

)后的文件 编译、汇编

C程序头文件。(为了节省时间,许多源文件会包含相同的头文件,GCC 允许事先编译好头文件,称为”预编译头文件”,它合适情况下自动被用于编译。) 通常不会出现在命令行

汇编语言。 汇编 gcc -c test.s -o test.o

gcc 是 GUN Compiler Collection的缩写。

预处理(pre-processing),E:插入头文件,替换宏,展开宏

gcc -E main.c -o main.i

编译(Compiling)S:编译成汇编

gcc -S main.i –o main.s

汇编(Assembling) c:编译成目标文件

gcc –c main.s –o main.o

链接 (Linking):链接到库中,变成可执行文件

gcc main.o –o main
./main

也可以一次性完成:

gcc main.c –o main

但一般情况下生成.o文件比较好,可以重定位文件,让别人使用

1.1 预处理

  • 处理所有的注释,以空格代替
  • 将所有的 #define删除, 并且展开所有的宏定义
  • 处理条件编译指令 #if, #ifdef, #elif, #else, #endif 处理条件编译指令
  • 处理处理 #include, 展开( evolve)被包含的文件
  • 保留编译器需要使用的 #pragma指令

C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开、文件包含、删除部分代码等。

在正常的情况下,GCC 不会保留预处理阶段的输出文件,也即 .i 文件。然而,可以利用 -E 选项保留预处理器的输出文件,以用于诊断代码。-E选项指示 GCC 在预处理完毕之后即可停止。

a、默认情况下,预处理器的输出会被导入到标准输出流(也就是控制台)

gcc -E main.c

b、可以利用-o选项把它导入到某个输出文件

gcc -E main.c -o main.i
 gcc -E main.c > main.i

表示把预处理的结果导出到 main.i 文件中。

c、使用 -C 选项阻止预处理器删除源文件和头文件中的注释。

注意,这里是大写的 -C,不是小写的 -c。小写的 -c 表示只编译不链接。

gcc -E -C main.c -o main.i

对比之前的输出,可以发现,保留愿文件中的注释

1.2 编译阶段

  • 对预处理文件进行一系列词法分析,语法分析和语义分析
  • 词法分析主要分析关健字,标示符,立即数等是否合法
  • 语法分析主要分析表达式是否遵循语法规则
  • 语义分析在语法分析的基础上进一步分析表达式是否合法
  • 分析结束后进行代码优化生成相应的汇编代码文件

编译器的核心任务是把C程序翻译成机器的汇编语言(assembly language)。

汇编语言是人类可以阅读的编程语言,也是相当接近实际机器码的语言。每种 CPU 架构都有不同的汇编语言。

实际上,GCC 是一个适合多种 CPU 架构的编译器,不会把C程序语句直接翻译成目标机器的汇编语言,而是在输入语言和输出汇编语言之间,利用一个中间语言,称为 RegisterTransfer Language(简称 RTL,寄存器传输语言)。借助于这个抽象层,在任何背景下,编译器可以选择最经济的方式对给定的操作编码。

通常情况下,GCC 把汇编语言输出存储到临时文件中,并且在汇编器执行完后立刻删除它们。但是可以使用-S选项,让编译程序在生成汇编语言输出之后立刻停止,而不删除临时文件。

-S可以理解为 Save 或者 Stop,自己的理解仅供参考记忆。

如果没有指定输出文件名,那么采用 -S选项的 GCC 编译过程会为每个被编译的输入文件生成以.s作为后缀的汇编语言文件。如下例所示:

gcc -S ts.c

编译器预处理 ts.c,将其翻译成汇编语言,并将结果存储在 ts.s 文件中,可以用文本编辑器察看.

指定输出文件名

gcc -S main.i -o filename.s

1.3 汇编阶段

  • 汇编器将汇编代码转变为机器可以执行的指令
  • 每个汇编语句几乎都对应一条机器指令

目标文件是一种中间文件或者临时文件,如果不设置该选项,gcc 一般不会保留目标文件,可执行文件生成完成后就自动删除了。

注意,使用-c选项表示只编译源文件,而不进行链接,因此,对于链接中的错误是无法发现的。

比如,调用一个不存在的函数,编译器会提示的错误。但是该命令不会输出错误信息。

gcc -c main.s -o main.o

-c选项:只编译不链接,仅生成目标文件。

1.4 链接阶段

gcc main.o -o main.exe

连接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接

静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序比较大。

动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。

动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。

这里用的clang/clang++ 分四步编译main.c/main.cpp文件

2.1 预处理

clang++ -E main.cpp -o main.ii

2.2 编译阶段,生成汇编

clang++ -S main.ii -o main.s

2.3 汇编阶段,生成目标文件

 clang++ -c main.s -o mian.o

2.4 连接阶段

 clang++ mian.o -o main

2.5 执行

 ./main

2.6 源文件

#include

int main() {
    std::cout << "Hello Biter !" << std::endl;
    return 0;
}

2.7 四部曲之一步到胃

clang++在编译的过程中,保存所有编译过程中产生的文件

2.8 产生中间文件

 clang++ -save-temps main.cpp -o main

2.9 不保存中间文件

 clang++  main.cpp -o main
  • 头文件
//
// Created by langkechanxin on 2021/1/7.

//

#define MAX(a,b) (((a)>(b)) ? (a) : (b))

int g_global = 10;
  • 源文件
//
// Created by langkechanxin on 2021/1/7.

//
#include "test.h"

#define LOW  0
#define HIGH 255

int max(int a, int b)
{
    return MAX(a,b);
}

int main()
{

    int c = max(LOW, HIGH); // Call max to get the larger number

    return 0;
}

预处理

gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.o

此时,借助 -c选项,生成的中间产物 test.o ,此文件为二级制文件, &#x901A;&#x8FC7; ls -l命令查看一下文件大小:

-rw-r–r– 1 binny staff 912B Jan 7 15:41 test.o

借助二进制文件查看器,比如 UltraEdit 可以查看到地址范围: 00000000h00000390(不包含)这是下一个字节的地址编号。一共 390hB=912B.

Original: https://www.cnblogs.com/burner/p/gcc-bian-yiccde-si-ge-guo-cheng.html
Author: 浪客禅心
Title: GCC编译C:C++的四个过程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606582/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球