动态库和静态库

静态库与动态库

基本概念

静态库(.a)动态库(.so)
本质多个 .o 文件的打包 + 索引(ranlib)编译好的二进制代码,运行时加载
链接时机编译时,将库代码复制进可执行文件运行时,由系统动态加载器加载
可执行文件大小大(包含库代码副本)小(只记录引用,不复制代码)
内存占用每个进程各有一份副本多个进程共享同一份物理内存
更新库需要重新编译整个程序替换 .so 文件即可,无需重新编译

什么时候用静态库?

  • 嵌入式系统/单片机:没有动态链接器或标准的 libc.so 可用
  • 独立部署:需要单个二进制文件跨机器运行,不依赖目标机器的库环境(如 Go 默认静态编译)
  • 早期开发/小型项目:自己写的小型库,还不涉及多程序共享,用 .a 更简单
  • 极端性能敏感:省去动态链接的运行时符号解析开销(影响通常可忽略)

什么时候用动态库?

  • 日常开发:默认选择,省空间、可共享、便于更新
  • 系统标准库(如 libc):几乎所有 C 程序都使用,如果每个程序静态链接一份,磁盘和内存浪费极大
  • 插件机制:通过 dlopen/dlsym 在运行时按需加载不同功能模块(如练习29)

系统库既有 .so 也有 .a

C 标准库通常同时提供两种版本:

  • libc.so.6 — 运行时默认使用的动态版本
  • libc.a — 静态版本,仅在编译时加 -static 标志时使用

验证方式:

1
2
3
4
5
6
7
# 查看可执行文件的动态库依赖
ldd ./myprog

# 静态编译(可执行文件大很多,不依赖动态库)
cc -static -o myprog myprog.c
ldd myprog
# 输出: "not a dynamic executable"

编译流程中的角色

1
2
3
4
5
6
.c 源文件 ──编译──→ .o 目标文件
        ┌────────────────┴────────────────┐
        ↓                                 ↓
   ar rcs 打包成 .a 静态库      链接阶段使用
   ranlib 建立索引              或编译为 .so 动态库

.h 头文件只提供声明(函数原型、结构体定义、宏),不包含实现。实现在 .c 中,编译成 .o,最终被打包进库中。

Licensed under CC BY-NC-SA 4.0
七弦绕明宫,知音且闻音,写作智音读作知音
使用 Hugo 构建
主题 StackJimmy 设计