静态库与动态库
基本概念
| 静态库(.a) | 动态库(.so) | |
|---|---|---|
| 本质 | 多个 .o 文件的打包 + 索引(ranlib) | 编译好的二进制代码,运行时加载 |
| 链接时机 | 编译时,将库代码复制进可执行文件 | 运行时,由系统动态加载器加载 |
| 可执行文件大小 | 大(包含库代码副本) | 小(只记录引用,不复制代码) |
| 内存占用 | 每个进程各有一份副本 | 多个进程共享同一份物理内存 |
| 更新库 | 需要重新编译整个程序 | 替换 .so 文件即可,无需重新编译 |
什么时候用静态库?
- 嵌入式系统/单片机:没有动态链接器或标准的 libc.so 可用
- 独立部署:需要单个二进制文件跨机器运行,不依赖目标机器的库环境(如 Go 默认静态编译)
- 早期开发/小型项目:自己写的小型库,还不涉及多程序共享,用
.a更简单 - 极端性能敏感:省去动态链接的运行时符号解析开销(影响通常可忽略)
什么时候用动态库?
- 日常开发:默认选择,省空间、可共享、便于更新
- 系统标准库(如 libc):几乎所有 C 程序都使用,如果每个程序静态链接一份,磁盘和内存浪费极大
- 插件机制:通过
dlopen/dlsym在运行时按需加载不同功能模块(如练习29)
系统库既有 .so 也有 .a
C 标准库通常同时提供两种版本:
libc.so.6— 运行时默认使用的动态版本libc.a— 静态版本,仅在编译时加-static标志时使用
验证方式:
| |
编译流程中的角色
| |
.h 头文件只提供声明(函数原型、结构体定义、宏),不包含实现。实现在 .c 中,编译成 .o,最终被打包进库中。