文章目录
一.程序实现的两个环境
任何一个C
程序的实现都要经过翻译环境与执行环境。
在翻译环境中又分为4个部分,预编译、编译、汇编与链接。在各个阶段主要完成的任务有:
- 预编译(预处理):头文件的包含、注释的删除、#define符号的替换
- 编译:将C语言代码转化为汇编代码
- 汇编:把汇编指令转化为二进制指令
- 链接:合并符号表和段表,生成可执行程序
二.gcc如何完成
通过gcc
指令的不同选项可查看各阶段所形成的文件
格式:gcc [选项] [目标文件名] -o [生成文件名]
首先在Test.c
文件中写好C
代码:
//Test.c
#include<stdio.h>
#define N 100
//这是一段注释.....
int main()
{
int n = 0;
printf("Hello World\n");
printf("%d\n", n + N);
return 0;
}
1.预处理
查看 Test.c
预处理后的结果,-E
选项的作用是让 gcc
在预处理结束后停止编译过程;-o
的作用是将预处理后的内容保存到 test.i
文件中
gcc -E Test.c -o test.i
如图所示,预处理阶段进行了头文件包含、注释的删除、#define的替换等。
2.编译
接下来将刚刚生成的 test.i
进行编译,并在编译之后停下来,将结果写入 test.s
中。gcc
所用选项为 -S
。
gcc -S test.i -o test.s
我们虽然可能没学习过汇编语言,但依旧隐约认识到这些就是汇编代码;可见编译阶段就是将C代码翻译为汇编指令。
3.汇编
gcc
所用选项为 -c
;-o
将结果写入到test.o
中。
gcc -c test.s -o test.o
正如我们所见,汇编完成之后都这这样的乱码。其实汇编之后,生成的文件为二进制文件,是用来给计算机看的,咱们已经看不懂了。
4.链接
编译完成之后就进入了链接阶段,链接完成之后就会生成可执程序 test
了。
gcc test.o -o Test
但是关于链接,我们需要知道它在链接什么。
比如为什么没有定义过函数 printf
、return
…等,但却可以使用它的功能?
其实,系统把这些函数的实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径
/usr/lib下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数 printf
了,而这也就是链接的作用。
三.动态库与静态库
函数库一般分为动、静态库两种。二者的区别可以理解为私有与公共的区别。就好比我们需要读一本《C和指针》,有两种方法可以选。一种是自己买一本,只有自己可以用,用起来还挺方便,缺点就是得花钱;第二种是去图书馆借书,图书馆的资源被所有人共享。
gcc
进行函数库的链接时可选择静态链接或者动态链接。
- 静态链接就类似于自己买书看,只给自己看同时还费钱(浪费内存),静态链接时会将库文件的代码全部加入到可执行文件中,因此生成的文件比较大。
- 动态链接类似于去图书馆借书。函数库就放在某个固定的地方,哪个程序想去使用就去自己去加载它。
Linux
下gcc
默认使用动态链接。
对比下二者生成的文件大小
//采用静态链接
gcc -static Test.c -o Test_static
//默认采用动态链接
gcc Test.c -o Test
若在静态链接时出错,可能是因为你的Linux
没有安装C语言的静态库,须手动安装。
//安装C语言静态库
yum install -y glibc-static
由此可见静态链接比动态链接生成的可执行文件大。
四.gcc常用选项
以下是gcc编译器常用选项汇总
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面;
-S 编译到汇编语言不进行汇编和链接;
-c 编译到目标代码;
-o 文件输出到 文件;
-static 此选项对生成的文件采用静态链接;
-g 生成调试信息。GNU 调试器可利用该信息;
-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.;
-O0
-O1
-O2
-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高;
-w 不生成任何警告信息;
-Wall 生成所有警告信息
本文到此结束,码文不易,还请多多支持哦!