1、背景知识
gcc是Linux中最常用的c编译器,只能用来编译c语言。g++支持多语言编译,跨平台开发,是基础开发必备工具。
今天我们来谈一下gcc编译程序(程序的编译过程) 翻译语言的本质是:转化成cpu能够识别的指令集
一共包含四步:
(1)预处理
1、头文件展开 2、去注释 3、宏替换 4、条件编译 在预处理完毕后还是c语言

源文件是:

test.i是:

gcc -E是用来进行与处理的指令,是将.c文件变为.i文件,预处理后会将stdio.h头文件中所有内容插入到test.中(这部分内容很多,这里省略大部分,只看和我们代码相关的部分)。可以看到PI被替换为3.14159,SQUARE(num)被替换为((num)*(num)),SQUARE(6)被替换为((6)*(6))
4、条件编译(在预处理阶段对代码进行"选择性裁剪")
|---------|------------------------------------|
| 指令 | 作用 |
| #if | 检查常量表达式是否为真,为真则编译后续代码 |
| #ifdef | 检查某个宏定义是否已经定义(不管宏的值是什么),已定义则编译后续代码 |
| #ifndef | 检查某个宏是否未定义,未定义则编译后续代码 |
| #else | 与 #if #ifdef #ifndef配合,处理"否则"的情况 |
| #elif | 相当于"else if",在#if 之后多条件分支判断 |
| #endif | 结束条件编译块,必须与前面的 #if #ifdef #ifndef |
[条件编译的预处理指令]

(2)编译(将c语言变为汇编语言)

输入上述代码后,程序开始编译,程序变为汇编语言就停下来。(如下图就是汇编语言)

(3)汇编
把汇编语言翻译成二进制文件(.o),这里的二进制文件全称是:可重定位目标二进制文件
cpp
gcc -c test.s -o test.o
执行完毕以上操作,就会形成下的文件:

(4)链接
把程序中调用库函数,和库本身函数实现产生关联的过程叫做链接。
在Linux中输入以下代码开始实现:
cpp
gcc test.o -o test
成功编译之后,就进入了链接阶段
2、动态链接和静态链接
在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每一个.c文件会形成一个.o文件,为了满足依赖关系,需要将这些源文件产生的目标文件进行链接,从而形成一个可执行的程序。这个链接的过程就是静态链接。
【学习语法(语言)其实是在学习编译器的规则】
如何理解动静态库?
|---------|------|------|
| | 静态库 | 动态库 |
| Linux | .a | .so |
| Windows | .lib | .ddl |
1、库的命名
lib.name.so(库真正的名字是name,即中间那一部分,去掉前缀lib和后缀so(无论静态库还是动态库))
2、动静态库
(1)静态链接:把库中方法(我们需要用到的),直接拷贝到你的程序中,叫做静态链接。
静态库和静态链接,,一旦链接成功,可执行程序就不再需要静态库。
动态链接:链接的是关联关系,链接的是地址。(一旦库缺失,所有相关程序就无法运行了)
以下是两种不同的库的对比:
|-----------------|-------------------------|
| 动态库 | 静态库 |
| .so | .a |
| 动态链接 | 静态链接 |
| 优点:节省内存空间 | 优点:不需要库跳转,一旦编译成功就不需要依赖库 |
| 缺点:慢,编译完依旧依赖动态库 | 缺点:可执行程序体积较大,消耗内存资源大 |

输入:file test

默认是动态链接的。所以可以得出结论:
gcc默认编译采用动态链接的方式,编译程序我们通常用动态库和动态链接是最佳实践
输入以下命令,强制要求gcc采用静态链接方式

file+文件名 ,查看 ,如下图:

静态库链接成功的大小是:
