4、警告選項
在編譯過程中,編譯器的報錯和警告信息對於程序員來說是非常重要的信息,GCC包含完整的出錯檢查和警告提示功能,它可以幫助Linux程序員盡快找出錯誤的或潛在的錯誤代碼,從而寫過更優美的代碼。GCC的編譯器警告選項如下表:
類型 | 說明 |
-Wall | 啟用所有警告信息 |
-Werror | 在發生警告時取消編譯操作,即將警告看作是錯誤 |
-w | 禁用所有警告信息 |
下面看一段代碼,使用GCC編譯,同時開啟警告信息:
#include <stdio.h> void main () { int x; for(x=1;x<=10;x++) { printf("%d\n",x); } }
對上面的代碼進行編譯連接:
$ gcc -Wall example3.c -o example3
example3.c:2:6: 警告: ‘main’的返回類型不是‘int’ [-Wmain]
從上面的輸出看到,GCC給出了警告信息,意思是main函數的返回值被聲明為void,但實際應該是int。
此外,GCC還提供了許多以-W開頭的選項,允許用戶指定輸出某個特定的警告,例如:
- -Wcomment:出現注釋嵌套時發出警告。
- -Wconversion:如果程序中存在隱式類型轉換,則發出警告。
- -Wformat:檢查printf和scanf等格式化輸入輸出函數的格式字符串和參數類型的匹配情況,如果發現不匹配則發出警告。
- -Winline:如果函數不能被內聯,則發出警告。
- -Wlong-long:如果使用了long long型數據,則發出警告。
- -Wmain:如果main函數的返回類型不是int型,或者調用main函數時使用的參數數目不正確,則發出警告。
- -Wmissing-declarations:如果定義了全局函數,但卻沒有在頭文件中聲明,則發出警告。
- -Wparentheses:在某些情況下,如果忽略掉了括號,則會發出警告。
- -Wreturn-type:如果函數定義了返回類型,而默認類型是int型,編譯器會發出警告。
- -Wuninitialized:如果使用的自動變量沒有被初始化,則發出警告。
- -Wundef:如果在#if宏中使用了未定義的變量做判斷,則發出警告。
- -Wunused:如果聲明的變量或static型函數沒有使用,則發出警告。
下面使用GCC編譯一段程序,來說明開啟警告信息的必要性:
#include<stdio> int main() { double x; printf("%d\n",x); /* 這里將%f誤輸為%d */ return 0; }
對上面的程序進行編譯:
$ gcc example4.c -o example4
可以看到,編譯並沒有報錯,運行可執行文件,輸出結果為:
$ ./example4
134513689
這不是想要的輸出結果,如果在上面的編譯中加入-Wformat或-Wall選項,即:
$ gcc -Wformat example4.c -o example4
或
$ gcc -Wall example4.c -o example4
GCC給出如下警告信息:
example4.c: 在函數‘main’中:
example4.c:5:5: 警告: 格式 ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
格式字符串和參數類型的不匹配會導致程序運行錯誤,所以這是是非常有用的警告選項。
下面使用GCC編譯一段程序,使用-Wparentheses選項對其中的括號進行檢查。
#include<stdio> int main() { int a=1; int b=0; int c=1; if(a&&b||c) { ; } if(a==1) if(b==1) printf("b=1\n"); else printf("b!=1\n"); return 0; }
對上面的程序進行編譯:
$ gcc -Wparentheses example5.c -o example5
example5.c: 在函數‘main’中:
example5.c:7:5: 警告: 建議在‘||’的操作數中出現的‘&&’前后加上括號 [-Wparentheses]
example5.c:11:7: 警告: 建議顯式地使用花括號以避免出現有歧義的‘else’ [-Wparentheses]
所以GCC編譯器的警告選項對程序員來說是非常重要的。
5、連接選項
GCC編譯器提供的連接器選項如下表:
類型 | 說明 |
-Idirectory | 向GCC的頭文件搜索路徑中添加新的目錄 |
-Ldirectory | 向GCC的庫文件搜索路徑中添加新的目錄 |
-llibrary | 提示連接程序在創建可執行文件時包含指定的庫文件 |
-static | 強制使用靜態鏈接庫 |
-shared | 生成動態庫文件 |
先來理解一下頭文件和庫文件這兩個概念:
頭文件包含變量和函數的聲明,但沒有定義函數的實現。函數的具體實現實在庫文件中完成的,庫文件可分為靜態庫和動態庫,靜態庫是指編譯連接時,將庫文件的代碼全部加入到可執行文件中,這樣運行時就不需要庫文件了。靜態庫的后綴名一般為“.a”。動態庫是指在編譯連接時並不將庫文件的代碼加入到可執行文件中,而是在程序執行時由運行時連接文件加載庫文件,這樣可以節省系統的開銷。動態庫的后綴名一般為“.so”。
例如我們編譯是用-I選項來指定頭文件的路徑:
$ gcc example.c –o example –I/home/xxx/include
頭文件所對應的庫文件,如果沒有特別指定時,GCC會到默認的搜索路徑進行查找。
使用-L選項來指定庫文件的路徑,例如:
$ gcc example.c –o example –L/home/xxx/lib
GCC編譯器在默認情況下使用動態庫,但如果使用了-static選項,連接器將忽略動態庫,強制使用靜態鏈接庫,即使用如下命令:
$ gcc example.c –o example –static –lm
此時靜態庫文件中的代碼全部包含到可執行文件中,所以生成的可執行文件比較大。
本節完…