庫是已經寫好的,成熟的,可以復用的代碼。本質上說來,庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。所謂的靜態,是指的鏈接過程。讓我們來看看將一個程序編譯成可執行程序的步驟:
當一個可執行程序由代碼變成可執行程序時,需要經過預編譯、編譯、匯編和鏈接。對於靜態庫,會在鏈接階段將匯編生成的目標.o文件與引用到的庫一起鏈接打包到可執行文件中,對於這種鏈接方式稱為靜態鏈接。靜態庫有如下特點:
上面也說了,靜態庫在程序編譯時會被鏈接到目標代碼中,程序運行時將不再需要該靜態庫;對於動態鏈接庫,在程序編譯時並不會被鏈接到目標代碼中,而是在程序運行時才被載入的,因此在程序運行時還需要動態鏈接庫。
由於鏈接後的可執行文件包含了所有需要調用的函數的代碼,所以可執行文件占用的磁盤空間較大。當多個調用相同LIB庫的程序在內存中運行時,內存中就存有多份相同的庫函數代碼,因此占用內存空間較多。對於動態鏈接庫,DLL不必被包含在最終的可執行程序中,可執行程序可以動態的加載和卸載DLL。我們都知道,Windows三個最基本的動態鏈接庫是:KERNEL32.DLL、USER32.DLL和GDI32.DLL;基本上每個程序都會使用這三個DLL,由於是動態鏈接庫,它們在內存中就存在一份拷貝,被不同的應用調用,這樣就避免了內存的浪費。由於靜態庫最終會被鏈接到可執行程序中去,這樣就會出現一個問題,當靜態庫發生變化時,那麼對應的可執行程序也需要進行重新編譯,這樣就導致了應用程序的更新變的極為困難。
首先創建一個Win32 Console Application程序,如下圖:
選擇Application type為Static library類型,就是靜態庫,如下圖:
添加Static_Lib.h和Static_Lib.cpp文件,在Static_Lib.h中添加以下代碼:
#ifndef _STATIC_LIB_H_ #define _STATIC_LIB_H_ int Add(int, int);#endif
在Static_Lib.cpp中添加以下代碼:
#include "stdafx.h"#include "Static_Lib.h"int Add(int a, int b){ return (a + b);}
進行編譯,會在工程的Debug目錄下生成一個LibDemo.lib靜態庫文件。
創建一個Client客戶端程序,負責調用LibDemo.lib靜態庫。客戶端代碼如下:
#include <iostream>#include "..\LibDemo\Static_Lib.h"using namespace std;#pragma comment(lib, "..\\LibDemo\\Debug\\LibDemo.lib")int main(int argc, char *argv[]){ cout<<Add(10, 20)<<endl; return 0;}
這樣就完成了(工程下載)。看了《在Visual Studio中使用C++創建和使用DLL》的童鞋就會好奇了,為什麼這個LIB的調用方式和DLL的加載時動態鏈接是一樣的?由於生成DLL時,也會創建一個.lib文件,而該lib文件和我們這裡說的LIB有很大的差別。和DLL一起生成的.lib文件,它只包含一些導出函數的聲明,並不包括函數的實現,沒有函數體,它只是為DLL服務的;而我們這裡說的LIB,是包括完整的函數實現的。
LIB學習起來很簡單,沒有多少東西可以講,也沒有什麼需要去注意的,但是,我們需要將LIB和DLL對比起來進行學習,這樣就能知道LIB的優點和缺點了。希望讀者能和我分享你對LIB的認識和見解。推薦閱讀《程序員的自我修養:鏈接、裝載與庫》(電子版下載)這本書。最後,祝願嫦娥三號登月成功。