动态/静态链接库详解
VS调用链接库常见问题及解决
头文件:编译时使用
Error C3861:找不到标识符
- C/C++ >> 附加包含目录 >> 写上头文件路径
.lib文件:链接时使用
Error LINK2019:无法解析的外部符号
- 链接器 >> 常规 >> 附加库目录 >> lib文件所在路径
- 链接器 >> 输入 >> 附加依赖项 >> lib文件的名字 (注意配置属性时 debug/release x86/x64 和项目相匹配)
.dll文件:运行时使用
缺失仍然可以编译通过
程序执行时弹窗报错:由于找不到.dll,无法继续执行代码,重新安装程序可能会解决此问题
-
将dll文件复制到exe文件同一目录下
-
或者:项目 >> 属性 >> 配置属性 >> 环境 PATH=%PATH%;E:\Qt\5.15.2\msvc2019_64\bin; 不同路径用分号隔开,记得加%PATH%不然无法调用系统SDK
动态/静态链接原理
静态连接
编译时需要:头文件.h + 链接库.lib
运行时不依赖外部文件
编译链接阶段,编译器会把你用到的静态库.lib文件中的代码完整复制到最终生成的可执行文件.exe里。.lib文件和最终生产的.exe文件都包含了函数的具体实现。
这种 .lib文件是完整的静态库,包含了库的所有二进制代码、数据、符号表等。比如你用 Visual Studio 链接 libcmt.lib(C 标准库的静态版本),链接器会把标准库中 printf、malloc 等函数的代码直接拷贝到你的 .exe 中。
动态链接
编译时需要:头文件.h + 链接库.lib
运行时依赖库对应的.dll文件
编译链接阶段,编译器不复制库代码,只在可执行文件中记录 “依赖的动态库.dll名称 + 函数入口地址”;程序运行时才加载对应的.dll文件,调用其中的代码。
这种 .lib`是**导入库,也叫 “链接库”,它不包含函数的具体实现,只包含:
- 动态库.dll的名称;
- 库中导出函数 / 变量的名称和地址偏移;
作用是告诉链接器:“我的代码在 XXX.dll 里,你只需要记录这个依赖,运行时再找它”。比如你链接 msvcrt.lib(C 标准库的动态导入库),最终 .exe 会依赖 msvcrt.dll,运行时系统会加载这个 DLL 并执行其中的函数。
那和直接给出函数定义的文件(如.cpp文件)有什么区别,链接库有什么用? .cpp文件是源代码文本文件,库文件是编译后的二进制代码,比如你可以调用Windows的API,但是不能看到其源代码一样。
链接库中的lib文件只要用到,则整个lib文件的内容都放进了.exe文件中,那它是被编译进去还是链接的时候连接进去的呢? 是在链接的时候将lib链接到目标代码中。
库代码分发方式
- 源代码:头文件.h + 源文件.cpp
- 动态链接库:头文件.h + lib文件 + dll文件
- 静态链接库:头文件 .h + lib文件
综合对比
| 维度 | 静态链接 | 动态链接 |
|---|---|---|
| 核心文件 | 静态库 .lib(含完整代码) | 导入库 .lib + 动态库 .dll |
| 代码整合时机 | 编译链接阶段 | 程序运行阶段 |
| 可执行文件体积 | 大(包含库代码) | 小(仅记录依赖) |
| 运行依赖 | 无(独立运行) | 依赖.dll(缺失则报错) |
| 库更新方式 | 重新编译链接整个程序 | 直接替换.dll即可 |
| 内存 / 磁盘占用 | 多个程序重复占用 | 多个程序共享.dll,节省资源 |