GCC有很多的編譯選項,警告選項;指定頭文件、庫路徑;優化選項。本文針整理一下GCC的警告選項以及gcc編譯警告整理和解決方法為中心而展開的討論。
一、GCC編譯警告總概
-w
禁止編譯警告的打印。這個警告不建議使用。大約2012年底,公司代碼進行一次大重構,另外從Codeblock集成開發環境轉向Makefile管理,Makefile里面默認使用了-w,因而代碼一直沒有警告,今年個別項目開發中發現一些代碼筆誤導致的BUG,而這些問題可以從編譯警告中知道。前幾個月,領導安排我來fix這些警告。為了自己,為了后人,不建議使用-w選項。
-Werror
將所有的警告當成錯誤處理。此選項謹慎建議加上。有的開源庫警告很多(大名鼎鼎的ffmpeg也有很多警告呢),一一改掉耗時耗人力,必要性也不大。最后,公司代碼加入了一個開源庫,里面有很多代碼警告,可能領導又安排我來fix了。
-Wfatal-errors
遇到第一個錯誤就停止,減少查找錯誤時間。建議加上。很多人遇到錯誤,沒有意識到從第一個開始排查。不管是編譯錯誤,還是程序運行出錯,從最開始的錯誤查起,是個好的做法。
-Wall開啟“所有”的警告。強烈建議加上,并推薦該選項成為共識。如case語句沒有default處理,有符號、無符號處理,未使用變量(特別是函數有大量未使用的數組,占用棧空間,測試發現,開辟一個未使用的8MB的數組,程序有coredump),用%d來打印地址,或%s打印int值,等,都可以發出警告。
-Wextra
除-Wall外其它的警告。建議加上。
在GCC編譯時,加上必要的警告選項,可以避免很多低級錯誤引發的問題,我就在實際工程代碼中遇到用“==”來賦值,我自己寫的代碼也出現過把“=”當成判斷的。但是,有些錯誤卻不是用GCC選項能解決的。比如一般項目都會自定義調試信息打印函數,但在處理可變參數類型時,往往不注意。可參考文章《一個可變參數類型檢查的示例》。
二、GCC編譯警告細化
上面只是大概講幾個重要的選項。由于GCC的警告選項太多了,下面盡自己能力寫一下。
-Wall選項,顧名思義,就是“所有”的意思,它包括:
[html] view plain copy-Wall包括:
-Waddress
-Warray-bounds=1 (only with -O2)
-Wc++11-compat -Wc++14-compat
-Wchar-subscripts
-Wenum-compare (in C/ObjC; this is on by default in C++)
-Wimplicit-int (C and Objective-C only)
-Wimplicit-function-declaration (C and Objective-C only)
-Wbool-compare
-Wduplicated-cond
-Wcomment
-Wformat
-Wmain (only for C/ObjC and unless -ffreestanding)
-Wmaybe-uninitialized
-Wmissing-braces (only for C/ObjC)
-Wnonnull
-Wopenmp-simd
-Wparentheses
-Wpointer-sign
-Wreorder
-Wreturn-type
-Wsequence-point
-Wsign-compare (only in C++)
-Wstrict-aliasing
-Wstrict-overflow=1
-Wswitch
-Wtautological-compare
-Wtrigraphs
-Wuninitialized
-Wunknown-pragmas
-Wunused-function
-Wunused-label
-Wunused-value
-Wunused-variable
-Wvolatile-register-var
但不要被它的表面意思迷惑,要不,怎么還會有-Wextra呢。-Wextra包括(有幾個選項重復了,不懂原因):
[html] view plain copy-Wclobbered
-Wempty-body
-Wignored-qualifiers
-Wmissing-field-initializers
-Wmissing-parameter-type (C only)
-Wold-style-declaration (C only)
-Woverride-init
-Wsign-compare
-Wtype-limits
-Wuninitialized
-Wshift-negative-value
-Wunused-parameter (only with -Wunused or -Wall)
-Wunused-but-set-parameter (only with -Wunused or -Wall)
-Wchar-subscripts:
使用char類作為數組下標(因為char可能是有符號數)
-Wcomment:
注釋使用不規范。如“/* */”注釋中還包括“/*”。我在項目源碼發現過,不止一處。
-Wmissing-braces
括號不匹配。在多維數組的初始化或賦值中經常出現。下面a沒有完整被初始化,b完整初始化:
int a[2][2] = { 0, 1, 2, 3 };
int b[2][2] = { { 0, 1 }, { 2, 3 } };
-Wparentheses
括號不匹配,在運算符操作或if分支語句中,可能會出現此警告。
如“a&&b||c^d”會出現警告。下面代碼片段也會有警告
{
if (a)
if (b)
foo ();
else
bar (); // 這個else實際是if (b)的分支,不是if (a),因此,要用括號來表明其屬于哪個分支
}
這類bug隱藏得深,建議顯式地加上括號。
-Wsequence-point
如出現i=i++這類代碼,則報警告。-Wall默認有該警告
-Wswitch-defaultcase
沒有default時,報警告
-Wunused-but-set-parameter
設置了但未使用的參數警告
-Wunused-but-set-variable
設置了但未使用的變量警告
-Wunused-function
聲明但未使用函數
-Wunused-label
未使用的標簽,比如用goto會使用label,但在刪除goto語句時,忘了刪除label。
-Wunused-variable
未使用的變量
-Wmaybe-uninitialized
變量可能沒有被初始化。特別是在有if語句或switch語句中,最好在聲明變量時加上初始化。
下面代碼片段中,當y不是1、2、3時,x沒有明確的值,是不安全的。
{
int x;
switch (y)
{
case 1: x = 1;
break;
case 2: x = 4;
break;
case 3: x = 5;
}
foo (x);
}
-Wfloat-equal
對浮點數使用等號,這是不安全的。
{
float d = 2.0;
if (d == i)
{
。。。
}
}
-Wreturn-type
函數有返回值,但函數體個別地方沒有返回值(特別是有if判斷,可能忘記在else添加返回值)。
int foo()
{
if(a==1)
{
return ok;
}
// no return here
}
-Wpointer-sign
指針有符號和無符號的錯誤傳參。如函數使用unsigned char*,但傳入char*指針。
-Wsign-compare
有符號和無符號比較。
-Wconversion-null
-Wsizeof-pointer-memaccess
在sizeof中經常出現,下面代碼片段中,this為指針,4字節,無法保證完整初始化類。
memset(this, 0, sizeof(this));
-Wreorder
C++出現,構造函數中成員變量初始化與聲明的順序不一致。
-Woverflow
范圍溢出。
-Wshadow
局部變量覆蓋參數、全局變量,報警告
評論
查看更多