处理所有以# 开头的代码,包括头文件、宏定义、条件编译
gcc -E hello.c -o hello.i
.i
标识预处理后的文件
#include<stdio.h> //从头文件展开
#define PRICE 10 //从宏定义直接替换
#if 0
void f1(){
print("haha");
}
#endif //条件编译,不满足条件直接扔掉
语法检查以及将C语言变成汇编语言
gcc -S hello.i -o hello.s
.s
标识汇编文件
将汇编语言变成二进制文件
gcc -c hello.s -o hello.o
链接代码需要用到的其他文件(库文件等)
gcc hello.o -o hello
静态链接是一种将程序的所有依赖库都打包到可执行文件中的链接方式。在静态链接中,编译器将源代码和所有依赖的库代码一起编译成一个单独的可执行文件,这样可执行文件就可以独立运行,不需要依赖外部的库文件。所以文件过大
使用 -static
进行静态链接
gcc hello.o -o hello -static
动态链接是一种将程序依赖的库在运行时从系统的共享库中加载的链接方式,仅仅只在生成的二进制文件中存放依赖文件的位置,因此文件较小
默认编译使用动态链接
用 ldd
命令查看可执行文件的依赖库以及路径:
ldd hello
-c : 只是编译不链接,生成目标文件.o
-S : 只是编译不汇编,生成汇编代码
-E : 只进行预编译,不做其他处理在可执行程序中包含标准调试信息
-o file : 把输出文件输出到file里
-V : 打印出编译器内部编译各过程的命令行信息和编译器的版本
-l dir : 在头文件的搜索路径列表中添加dir目录
-L dir : 在库文件的搜索路径列表中添加dir目录
-l<library>:按照-L 指定的路径去搜索指定的库
-static:链接静态库
-I library :连接名为library的库文件
静态库是一种预编译的二进制文件,包含了一组函数、类或模块的实现代码。它们被编译成目标文件(通常是
.o
或.obj
),然后打包成静态库文件(通常是.a
或.lib
)。
3.1.1 优点:
- 独立性:静态库将代码和依赖的函数或模块打包在一起,使得可执行文件具有独立性,不需要依赖外部的库文件。
- 性能:静态库的代码在编译时就已经被链接到可执行文件中,因此可以减少运行时的依赖和加载时间。
- 简化部署:静态库文件可以简化软件的部署过程,只需将可执行文件和静态库文件一起传递给用户即可。
3.1.2 创建和使用静态库:
-
创建静态库:首先,将相关的源文件编译成目标文件,然后使用静态库工具(如
ar
)将这些目标文件打包成静态库文件。例如:gcc -c mylib.c -o mylib.o ar rcs libmylib.a mylib.o //lib<库名>.a
-
使用静态库:在编译可执行文件时,使用
-l
选项指定需要链接的静态库文件。例如:gcc main.c -o myprogram -static -L . -lmylib
-static
代表编译时使用静态编译,-L
代表在当前目录下找库文件,-lmylib
代表链接到mylib
的静态库
3.2.1 定义
动态库是一种共享的二进制文件,包含了一组函数、类或模块的实现代码。它们被编译成共享目标文件(通常是
.so
或.dll
),在运行时从系统的共享库中加载
3.2.2 优点
- 共享性:多个程序可以共享同一个动态库的实例,减少内存占用。
- 灵活性:动态库可以在运行时加载和卸载,可以动态更新和替换,而无需重新编译和链接依赖该库的程序。
- 版本管理:动态库可以支持版本管理,允许不同版本的库共存,并允许程序选择使用特定版本的库。
3.2.3 创建和使用动态库
创建动态库:首先,将相关的源文件编译成共享目标文件,然后使用动态库工具(如 gcc
)将这些目标文件链接成动态库文件。例如:
gcc -shared -o libmylib.so mylib.c //动态库lib<name>.so
使用动态库:在编译可执行文件时,使用 -l
选项指定需要链接的动态库文件。例如:
gcc main.c -o myprogram -lmylib
3.2.4 检查动态库的内容:
使用 nm
命令:可以用于查看动态库的符号表信息,包括库中定义的函数和变量。例如,使用以下命令列出动态库libmylib.so
nm -D libmylib.so