抛出几个概念:库、静态库、动态库、链接、静态链接、动态链接、显示链接、隐式链接。
若不明白,请继续往下看。
什么是库
库:库是写好的现有的、成熟的、可以复用的代码。库和可执行文件的区别是:库不是独立程序,它是向其他程序提供服务的代码。
有哪些库
有两种库:静态库(.a、.lib)和动态库(.so、.dll),它们是两种共享程序代码的方式。
静态库(Static library/Static link library):lib包含代码本身,在编译时直接将代码加入到程序当中。在可执行文件中包含了库代码的一份完整拷贝。vs编译成功后,只会生成一个.lib文件。
动态库(Dynamic library/Dynamic link library):lib包含了函数所在的dll和dll中函数位置的入口信息。代码由运行时加载在进程空间中的dll提供。vs编译成功后,会生成两个文件.lib文件和.dll文件。
静态库和动态库中的lib有什么区别
静态库中的lib:包含函数代码本身(包括函数的索引和实现),在编译时直接将代码加入程序当中。
动态库中的lib:包含函数所在的dll文件和文件中函数位置的索引,函数实现的代码由运行时加载到进程空间中的dll提供。
所以:lib是编译时用到的,dll是运行时用到的。如果要完成代码的编译,只需要lib,如果要使动态链接的程序运行起来,只需要dll。
链接的方式
链接器将一个个目标文件(或许还有若干程序库)链接在一起生成一个完整的可执行文件。
静态链接:使用静态链接库,链接器从静态链接库lib获取所有被引用函数,并将库同代码一起放到可执行文件中。
动态链接:使用动态链接库,允许可执行模块(.dll文件或者.exe文件)仅包含在运行时定位dll函数的可执行代码所需的信息。
隐式链接与显式链接
隐式链接与显式链接是怎么回事呢?其实这两种链接方式只是dll的两种不同的加载方式而已。
隐式链接:1.Property->Linker->Input->Additional Dependencies中添加.lib文件,或者在源代码中加入指令#pragma comment(lib,"XX.lib")
2. Property->Linker->Input->Additional Library Directories中配置.lib文件所在的相对路径
3. 将.dll文件置入工程所在目录,然后添加对应的.h头文件
显式链接:需要函数指针和WIN32 API函数:LoadLibrary、GetProcAddress装载,使用这种载入方式,不需要.lib文件和.h头文件,只需要.dll文件即可(将.dll文件放到工程目录中)。
写一个静态库以及如何使用静态库:
1.新建Win32 Project工程,Application type选择Static library类型。新建的工程中有stdafx.h和cpp,在上一篇博文中已介绍。
2.这次就写一个支持加/减操作的lib,新增MyMath.h和MyMath.cpp。

1 #ifndef _MY_STATIC_LIB_H_ 2 #define _MY_STATIC_LIB_H_ 3 4 class MyMath 5 { 6 public: 7 MyMath(); 8 ~MyMath(); 9 10 int Add(int nNumA, int nNumb); 11 int Sub(int nNumA, int nNumb); 12 }; 13 #endif // _MY_STATIC_LIB_H_
MyMath.cpp

1 #include "stdafx.h" 2 #include "MyMath.h" 3 4 MyMath::MyMath() 5 { 6 } 7 8 MyMath::~MyMath() 9 { 10 } 11 12 int MyMath::Add(int nNumA, int nNumb) 13 { 14 return nNumA + nNumb; 15 } 16 17 int MyMath::Sub(int nNumA, int nNumb) 18 { 19 return nNumA - nNumb; 20 }
接下来就新建一个exe工程,我们就取名:UseLibraryTest,该工程需要以下配置:
1.属性C/C++->General->Additional Include Directories要配置MyMath.h文件所在的相对路径。
2.属性Linker->General->Additional Library Directories要配置MyMath.lib文件所在的相对路径。
3.属性Linker->Input->Additional Dependencies中添加MyMath.lib。这一步或者可以改为在使用该lib的工程cpp中添加:#pragma comment(lib, "MyMath.lib")
4.最后在使用的cpp中添加#include <MyMath.h>

1 #include "stdafx.h" 2 #include <MyMath.h> 3 #include <iostream> 4 5 using namespace std; 6 7 int main() 8 { 9 MyMath MyMath; 10 int nNumA = 10; 11 int nNumB = 10; 12 int nResult = 0; 13 14 nResult = MyMath.Add(nNumA, nNumB); 15 cout << nResult << endl; 16 17 nResult = MyMath.Sub(nNumA, nNumB); 18 cout << nResult << endl; 19 20 return 0; 21 }
在第3步中,若改为用#pragma comment(lib, "MyMath.lib")的代码如下:

1 #include "stdafx.h" 2 #include <MyMath.h> 3 #include <iostream> 4 #pragma comment(lib, "Static Library.lib") 5 6 using namespace std; 7 8 int main() 9 { 10 MyMath MyMath; 11 int nNumA = 10; 12 int nNumB = 10; 13 int nResult = 0; 14 15 nResult = MyMath.Add(nNumA, nNumB); 16 cout << nResult << endl; 17 18 nResult = MyMath.Sub(nNumA, nNumB); 19 cout << nResult << endl; 20 21 return 0; 22 }
如果第1步没有设置,则编译时会报错:fatal error C1083: Cannot open include file: 'MyMath.h': No such file or directory
如果第2步没有设置,并且lib也没有在该工程目录的情况下,则链接时会报错:LINK : fatal error LNK1104: cannot open file 'Static Library.lib'
如果第3步没有设置,会报错:
1> UseLibraryTest.cpp
1>UseLibraryTest.obj : error LNK2019: unresolved external symbol "public: __thiscall MyMath::MyMath(void)" (??0MyMath@@QAE@XZ) referenced in function _main
1>UseLibraryTest.obj : error LNK2019: unresolved external symbol "public: __thiscall MyMath::~MyMath(void)" (??1MyMath@@QAE@XZ) referenced in function _main
1>UseLibraryTest.obj : error LNK2019: unresolved external symbol "public: int __thiscall MyMath::Add(int,int)" (?Add@MyMath@@QAEHHH@Z) referenced in function _main
1>UseLibraryTest.obj : error LNK2019: unresolved external symbol "public: int __thiscall MyMath::Sub(int,int)" (?Sub@MyMath@@QAEHHH@Z) referenced in function _main
如果第4步没有做,会报错:error C2065: 'MyMath' : undeclared identifier等
我举出这么多报错的情况,只是为了让你能够熟悉这些错误。如果有一天有这样的报错,就能够快速的定位。。多看看报错信息也是很重要的,以提高解决bug的能力。