C/C++ 程序编译过程、静态/动态链接、静态/动态库

一、编译的四个阶段

1.预处理(进行宏替换)

预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
预处理指令是以#号开头的代码行。

bash 复制代码
gcc -E code.c -o code.i

2.编译(生成汇编)

在这个阶段中,gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,
在检查无误后,gcc 把代码翻译成汇编语言。

bash 复制代码
gcc --S hello.i --o hello.s

3.汇编(生成机器可识别代码)

将汇编代码转换为二进制机器码。

bash 复制代码
gcc --c hello.s --o hello.o

4.连接(生成可执行文件或库文件)

链接器(Linker)将多个目标文件和库文件合并成一个完整的可执行文件。它会解决所有未定义的符号引用,将它们指向正确的地址。链接器还会将程序使用的标准库函数(如 printf)合并进来。

bash 复制代码
gcc hello.o --o hello

二、实际项目应用

在真实的软件开发中,一个项目通常由多个源文件(.c文件)组成。我们通常会分别将每个源文件编译为目标文件,而不是一次性编译整个项目。这可以通过以下方式实现:

bash 复制代码
# 分别编译每个源文件为目标文件
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
gcc -c file3.c -o file3.o

或:

bash 复制代码
gcc -c file1.c
gcc -c file2.c
gcc -c file3.c

这会产生对应的 file1.o、file2.o、file3.o文件。这种分离编译的方式有以下几个优点:

  1. 当只修改其中一个源文件时,只需重新编译该文件,而不用重新编译整个项目,提高了编译效率。

  2. 便于团队协作,不同开发者可以并行编译各自负责的模块。

  3. 便于将代码组织成库文件。

最后一起链接:

bash 复制代码
# 将所有目标文件链接成一个可执行文件
gcc file1.o file2.o file3.o -o myprogram

当只修改其中一个源文件时,只需重新编译该文件,而不用重新编译整个项目,提高了编译效率。

操作系统是怎么做到的??

看时间戳

Linux 里每个文件都有 3 个时间,用 stat 文件名 可以看到:

atime :访问时间(cat、vim 打开看一下,就变)

mtime :修改时间(内容改了才变)

ctime :状态改变时间(权限、改名等)

操作系统只关心一个:mtime(修改时间)

只查看文件 → mtime 不变,make 就认为文件没动 → 不会重新编译

修改文件、保存文件 → mtime 变 → 会重新编译

判断流程:

比较目标文件和依赖文件的 mtime

如果依赖文件比目标文件更新(mtime 更大)→ 执行命令

如果目标文件不存在 → 执行命令

否则 → 跳过("目标已是最新的")


三、静态链接 vs 动态链接

在实际开发中,多个源文件之间存在依赖关系,需要将它们产生的目标文件进行链接。链接方式有两种:

1.静态链接

在编译时,将库文件的代码全部复制到可执行文件中。

优点:

可执行文件独立,不依赖外部库文件。

启动速度快(代码在进程地址空间内)

缺点:

浪费空间(多个程序包含相同库的副本)

更新困难(库更新需重新编译整个程序)

可执行文件体积较大

2.动态链接

在程序运行时才加载库文件。程序启动稍慢,但内存占用少。

例如:

我们的C程序中调用的 printf()函数,实现在哪里?

C标准只定义了函数声明(在 stdio.h中),函数实现位于系统的C标准库中:

Linux: libc.so.6(动态库)或 libc.a(静态库)

Windows: msvcrt.dll或 libcmt.lib

核心:让程序找到库中方法的地址!

四、静态库/动态库

1.静态库

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,其后缀名⼀般为".a"

静态库本身是一个文件(例如 libmymath.a),它本质上是一个或多个目标文件(.o文件)的打包集合 。创建它的目的是为了代码复用。

2.动态库

动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由
运行时链接文件加载库,这样可以节省系统的开销。动态库⼀般后缀名为".so"

gcc默认生成的二进制程序,是动态链接的。gcc 在编译时默认使用动态库。
可以使用 -static 强制全部静态链接。

相关推荐
一技安身12 小时前
MySQL 8.4.13 LTS 通用二进制包(Linux免安装版)完整教程
linux·mysql·adb
迷途之人不知返12 小时前
【动态库与静态库】-3-静态链接与加载
linux
谙弆悕博士13 小时前
debian快速换源
linux·运维·windows·debian·下载·换源·网络问题
.道阻且长.13 小时前
Linux基本开发工具:编译器gcc/g++
linux·运维·服务器·职场和发展
Industio_触觉智能13 小时前
瑞芯微RK系列调试工具与量产测试手册-上|串口日志打通与JTAG兜底调试
linux·sdk·jtag·瑞芯微·调试工具·rk3576·量产调试
HideF1 天前
Linux
linux·服务器·网络
Ruiery1 天前
Linux 6.6内核内存管理深度解析(十三):slab/slub 分配器
linux·运维·服务器
丰锋ff1 天前
压缩命令笔记
linux
GeW1 天前
产业新优势基础软件的人才底盘,从Linux与数据库开始
linux·数据库
by209991 天前
Linux GCC/G++ 编译与 Makefile 构建
linux·运维·服务器·经验分享