文章目录
- 背景知识
- gcc的使用
- 预处理(进行宏替换)
- 编译(生成汇编)
- 汇编(生成机器可识别代码)
- 连接(生成可执行文件或库文件)
- gcc选项
- 函数库
- 函数库一般分为静态库和动态库两种
- C/C++静态库的安装
背景知识
g++是编译cpp代码的编译器,而gcc是编译c语言的编译器,它们的选项都是一样的,所以本章主要就介绍gcc。
- 预处理(进行宏替换)
- 编译(生成汇编)
- 汇编(生成机器可识别代码)
- 连接(生成可执行文件或库文件)
关于这些不了解的可以看看这篇文章:程序环境
gcc的使用
格式:
gcc [选项] 要编译的文件 [选项] [目标文件]
预处理(进行宏替换)
- 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
- 预处理指令是以#号开头的代码行。
- 实例:
gcc –E hello.c –o hello.i
- 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
- 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
编译(生成汇编)
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
- 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
- 实例:
gcc –S hello.i –o hello.s
汇编(生成机器可识别代码)
- 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
- 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
- 实例:
gcc –c hello.s –o hello.o
连接(生成可执行文件或库文件)
- 在成功编译之后,就进入了链接阶段。
- 实例:
gcc hello.o –o hello
gcc选项
-E
只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面-S
编译到汇编语言不进行汇编和链接-c
编译到目标代码-o
文件输出到 文件-static
此选项对生成的文件采用静态链接-g
生成调试信息。GNU 调试器可利用该信息。- -
shared
此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库. -O0
-O1
-O2
-O3
编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高-w
不生成任何警告信息。-Wall
生成所有警告信息。-std=c99
指定了编译器应遵循C语言的C99标准进行编译-std=c11
指定了编译器应遵循C语言的C11标准进行编译
函数库
- 我们的C程序中,并没有定义
printf
的函数实现,且在预编译中包含的stdio.h
中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实printf
函数的呢? - 最后的答案是:系统把这些函数实现都被做到名为
libc.so.6
的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径/usr/lib
下进行查找,也就是链接到libc.so.6
库函数中去,这样就能实现函数printf
了,而这也就是链接的作用。
函数库一般分为静态库和动态库两种
- 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为
.a
,Windows系统下后缀名一般为.lib
- 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为
.so
,Windows系统下后缀名一般为.dll
,如前面所述的libc.so.6
就是动态库。gcc
在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。gcc hello.o –o hello
- gcc默认生成的二进制程序,是动态链接的,这点可以通过 ldd 命令验证。
ldd 查看一个可执行程序所依赖的库文件。使用方式如下:
ldd [可执行文件名]
我们在使用gcc或者g++编译一个源文件时,默认是使用动态链接的方式区编译,如果想使用静态链接的话,要带上选项-static
C/C++静态库的安装
但是在这之前,要先确保是否安装得有静态库,否则就会出现以下报错
如果没有的话,可以登录root账户使用以下命令来进行安装:
yum install -y glibc-static libstdc++-static
这两个可执行文件是我分别使用动静态库链接编译形成的可执行文件。可以看出它们的体积大小差距还是挺大的。
静态库
优点:不依赖库,同类型平台中都可以直接运行使用。
缺点:可执行程序体积比较大,比较浪费资源。
动态库
优点:比较节省资源(磁盘,内存,网络等),不会出现太多的重复代码。
缺点:对库的依赖性比较强,一旦库丢失,所有使用这个库的程序都无法运行。