在 C 程序中调用 动态库 和 静态库 时,编译和执行的方式存在一些重要的区别。这主要体现在库的链接方式、程序的体积、执行时的依赖以及编译命令上。下面详细说明动态库和静态库的区别以及它们的编译与执行方式。
1. 静态库(Static Library)
特点:
- 文件格式:静态库的文件通常以
.a
(Linux/Unix)或.lib
(Windows)为后缀。 - 链接时机:静态库在 编译时 链接,编译器会将静态库的代码直接拷贝到生成的可执行文件中。
- 体积:由于库的代码被嵌入到可执行文件中,最终生成的可执行文件体积会变大。
- 执行依赖:静态库在编译时已被嵌入到可执行文件中,因此不依赖外部的库文件,程序可以独立运行。
编译和链接方式:
假设有一个静态库文件 libmylib.a
,并且我们有一个源文件 main.c
,在编译和链接时,可以使用以下命令:
gcc -o myprogram main.c -L. -lmylib
-L.
:表示链接目录为当前目录(即静态库所在目录)。-lmylib
:表示链接名为libmylib.a
的静态库(-l
后面不用写前缀lib
和后缀.a
)。
执行方式:
编译成功后,生成的可执行文件 myprogram
可以直接运行,不需要额外的库文件。
./myprogram
2. 动态库(Shared Library)
特点:
- 文件格式:动态库的文件通常以
.so
(Linux/Unix)或.dll
(Windows)为后缀。 - 链接时机:动态库在 运行时 链接,程序运行时会从指定的路径加载动态库,而不是将库的代码嵌入到可执行文件中。
- 体积:由于可执行文件只包含对库的引用,而不包含库的实际代码,因此程序的体积较小。
- 执行依赖:程序执行时依赖于动态库,必须确保动态库文件在运行时可以找到。
编译和链接方式:
假设有一个动态库文件 libmylib.so
,并且我们有一个源文件 main.c
,在编译和链接时,可以使用以下命令:
gcc -o myprogram main.c -L. -lmylib
- 这里的编译命令和静态库的编译命令是相似的,
-L.
指定库的路径,-lmylib
指定要链接的动态库libmylib.so
。 - 但在这个过程中,GCC 默认会优先链接动态库
.so
文件(如果找不到动态库,才会使用静态库)。
执行方式:
与静态库不同的是,动态库必须在运行时能被找到。如果动态库不在默认的系统库路径中,需要设置环境变量 LD_LIBRARY_PATH
来指定动态库的路径。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./myprogram
LD_LIBRARY_PATH
环境变量用于告诉系统去哪里查找动态库。如果动态库位于当前目录(.
),需要将当前目录添加到LD_LIBRARY_PATH
。
3. 编译与执行的主要区别
特性 | 静态库 | 动态库 |
---|---|---|
文件后缀 | .a (Linux/Unix),.lib (Windows) | .so (Linux/Unix),.dll (Windows) |
链接时机 | 编译时 | 运行时 |
程序体积 | 较大,库代码嵌入到可执行文件中 | 较小,库代码不嵌入,运行时动态加载库文件 |
执行依赖 | 没有外部库的依赖,生成的可执行文件是自包含的 | 必须有动态库文件存在,程序运行时依赖动态库 |
执行性能 | 稍快,库的代码已经嵌入可执行文件中 | 稍慢,程序运行时需要从外部加载库(但通常区别不大) |
库的更新 | 更新库需要重新编译整个程序 | 可以独立更新库文件而不需要重新编译整个程序 |
命令示例 | gcc -o myprogram main.c -L. -lmylib | gcc -o myprogram main.c -L. -lmylib |
执行方式 | 直接执行:./myprogram | 可能需要设置 LD_LIBRARY_PATH :export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH && ./myprogram |
4. 总结
- 静态库:库在编译时链接到可执行文件中,生成的程序体积大,执行时不依赖外部库,可以独立运行。
- 动态库:库在运行时加载,生成的程序体积小,但执行时依赖外部库,程序运行时需要找到库文件。
根据你的需求,你可以选择使用静态库或动态库:
- 如果你希望程序可以独立运行,避免外部依赖,使用静态库。
- 如果你希望程序体积小且可以随时更新库文件而不重新编译程序,使用动态库。