拋出幾個概念:庫、靜態庫、動態庫、鏈接、靜態鏈接、動態鏈接、顯示鏈接、隱式鏈接。
若不明白,請繼續往下看。
什么是庫
庫:庫是寫好的現有的、成熟的、可以復用的代碼。庫和可執行文件的區別是:庫不是獨立程序,它是向其他程序提供服務的代碼。
有哪些庫
有兩種庫:靜態庫(.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的能力。