gcc支持的預(yù)處理指令:
#include // 將指定文件的內(nèi)容插至此指令處
#define // 定義宏
#undef // 刪除宏
#if // 判定
#ifdef // 判定宏是否已定義
#ifndef // 判定宏是否未定義
#else // 與#if玖像、#ifdef纸颜、#ifndef結(jié)合使用
#elif // else if多選分支
#endif // 結(jié)束判定
## // 連接宏內(nèi)兩個連續(xù)的字符串
# // 將宏參數(shù)擴展成字符串字面值
#error // 預(yù)處理時產(chǎn)生錯誤握联,結(jié)束預(yù)處理
#warning // 預(yù)處理時產(chǎn)生警告信息
#pragma // 提供額外信息的標準方法教藻,可用于指定平臺
#pragma GCC dependency <文件> // 若<文件>比此文件新則產(chǎn)生警告
#pragma GCC poison <標識> // 若出現(xiàn)<標識>則產(chǎn)生錯誤
#pragma pack(1/2/4/8) // 按1/2/4/8字節(jié)對齊補齊
#line // 指定行號
gcc預(yù)定義的宏:
void printf_macro (void)
{
printf ("__FILE__ : %s\n", __FILE__); //獲取當前文件名
printf ("__LINE__ : %d\n", __LINE__); //獲取行號
printf ("__FUNCTION__ : %s\n", __FUNCTION__); //獲取函數(shù)名
printf ("__func__ : %s\n", __func__); //獲取函數(shù)名
printf ("__DATE__ : %s\n", __DATE__); //獲取日期(字符串)
printf ("__TIME__ : %s\n", __TIME__); //獲取時間
printf ("__cplusplus : %d\n", __cplusplus); //g++編譯輸出1;gcc編譯輸出0
}
通過修改配置文件設(shè)置:
Linux系統(tǒng)的修改方法
# 打開配置文件:
vi ~/.bashrc # 只對當前用戶用效
vi /etc/environment # 對所有用戶有效
# 在文件末尾添加內(nèi)容:
export C_INCLUDE_PATH=<環(huán)境變量的內(nèi)容>
C_INCLUDE_PATH=$C_INCLUDE_PATH:<追加新的內(nèi)容>
# 重新加載配置文件:
source ~/.bashrc
image.png
創(chuàng)建靜態(tài)庫:
# 編譯出目標文件:
gcc -c xxx1.c
gcc -c xxx2.c
...
# 把目標文件打包成靜態(tài)庫文件
ar -r libxxx.a x1.o x2.o ...
# ar 是一個專門控制靜態(tài)庫的命令
-r # 把目錄文件合并成一個靜態(tài)庫,如果靜態(tài)庫文件已經(jīng)存在則更新。
-q # 向靜態(tài)庫中添加目標文件
-t # 查看靜態(tài)庫中有哪些目標文件
-d # 從靜態(tài)庫中刪除目標文件
-x # 把靜態(tài)庫展開為目標文件
使用靜態(tài)庫:
# 方法1、直接調(diào)用婶肩,把共享庫當作目標文件一樣,與調(diào)用者的目標文件一起合并出可執(zhí)行文件貌夕。
gcc main.c libxxx.a
# 方法2律歼、通過設(shè)置LIBRARY_PATH環(huán)境變量來指定庫的路徑,通過-l參數(shù)來指定庫名
gcc main.c -lxxx
# 方法3啡专、通過gcc -L參數(shù)來指定庫的路徑险毁,通過-l參數(shù)來指定庫名
gcc main.c -L<PATH> -lxxx
創(chuàng)建動態(tài)庫:
# 編譯出目標文件,-fpic編譯出位置無關(guān)代碼们童,在代碼中使用相對地址畔况,這樣共享庫就可以加載到內(nèi)存的任何位置。
gcc -c -fpic xxx1.c
gcc -c -fpic xxx2.c
...
# 把目標文件打包成共享庫:
gcc -shared xxx1.o xxx2.o ... -o libxxx.so
使用動態(tài)庫:
# 方法1慧库、直接調(diào)用
gcc main.c libxxx.so
# 方法2跷跪、通過設(shè)置LIBRARY_PATH環(huán)境變量來指定庫的路徑,需要通過-l來指定庫名
gcc main.c -lxxx
# 3齐板、通過gcc -L參數(shù)來指定庫的路徑
gcc main.c -L<PATH> -lxxx
# 注意1:如果執(zhí)行無法運行吵瞻,需要檢查操作系統(tǒng)是否能加載動態(tài)庫葛菇,檢查LD_LIBRARY_PATH環(huán)境變量
# 注意2:如果靜態(tài)庫和共享庫同時存在,優(yōu)先使用共享庫橡羞,通過-static可以指定使用靜態(tài)庫熟呛。
靜態(tài)庫的優(yōu)點:
使用方便,運行速度快:
在鏈接目標文件生成程序時尉姨,只需要把靜態(tài)庫與目標文件一起編譯,編譯器就會把目標文件中使用到的靜態(tài)的內(nèi)容拷貝到程序中吗冤,程序在運行時就不需要靜態(tài)庫了又厉。
靜態(tài)庫的缺點:
更新麻煩:
使用了相關(guān)靜態(tài)庫的程序需要重新編譯,如果是應(yīng)用程序椎瘟,用戶就需要重新下載覆致。
浪費內(nèi)存:
代碼的拷貝造成了冗余,造成內(nèi)存的浪費肺蔚。
動態(tài)庫的缺點:
在鏈接目標文件時煌妈,雖然動態(tài)庫需要與使用它的目標文件一起編譯,但編譯器只是記錄被調(diào)用的內(nèi)容(函數(shù)宣羊、變量)在動態(tài)庫中的位置璧诵,生成的程序中只有跳轉(zhuǎn)到動態(tài)庫的相關(guān)指令,當執(zhí)行到動態(tài)庫的相關(guān)內(nèi)容時仇冯,才跳轉(zhuǎn)到動態(tài)庫所在的內(nèi)存中執(zhí)行之宿,完成后再返回。
運行速度慢:
使用動態(tài)庫程序需要在程序和動態(tài)庫中來回跳轉(zhuǎn)苛坚,因此要比使用靜態(tài)庫的程序運行的速度慢比被。
程序無法執(zhí)行:
如果系統(tǒng)找不到相應(yīng)的動態(tài)庫,那么程序就無法運行(Windows系統(tǒng)經(jīng)常提示的xxx.dll文件缺失泼舱,程序無法運行)等缀,產(chǎn)生這種錯誤的原因有很多,如:環(huán)境變量配置錯誤娇昙,動態(tài)庫文件存儲位置錯誤尺迂。
總結(jié):當一個模塊不會再發(fā)生改變,并且執(zhí)行速度有一些要求涯贞,適合把它封裝成靜態(tài)庫枪狂。
動態(tài)庫的優(yōu)點:
節(jié)約內(nèi)存:
使用的動態(tài)庫只需被系統(tǒng)加載一次,不同的程序都可以使用到內(nèi)存中的動態(tài)庫宋渔,因此節(jié)約了很多內(nèi)存州疾,由于多個程序可共享使用一個動態(tài)庫,所以動態(tài)庫也叫共享庫皇拣。
更新方便:
如果動態(tài)庫中的函數(shù)格式?jīng)]有變化(返回值严蓖、函數(shù)名薄嫡、參數(shù)列表),而只是函數(shù)中的業(yè)務(wù)邏輯代碼發(fā)生變化颗胡,那么只需要重新編譯動態(tài)庫即可毫深,不需要重新編譯相關(guān)的可執(zhí)行文件,這也是某些應(yīng)用程序可以自動更新的原因毒姨。
總結(jié):隨著計算機性能的不斷提升哑蔫,彌補了動態(tài)庫運行速度慢的缺點,再加上它能節(jié)約內(nèi)存弧呐、更新方便闸迷,最主要的是計算機硬件一直在升級,所以就導(dǎo)致大多數(shù)代碼需要不斷的升級俘枫,因此我們大多數(shù)情況下把模塊封裝成動態(tài)庫腥沽。