GCC有很多的編譯選項(xiàng),警告選項(xiàng);指定頭文件、庫(kù)路徑;優(yōu)化選項(xiàng)。本文針整理一下GCC的警告選項(xiàng)以及gcc編譯警告整理和解決方法為中心而展開的討論。
一、GCC編譯警告總概
-w
禁止編譯警告的打印。這個(gè)警告不建議使用。大約2012年底,公司代碼進(jìn)行一次大重構(gòu),另外從Codeblock集成開發(fā)環(huán)境轉(zhuǎn)向Makefile管理,Makefile里面默認(rèn)使用了-w,因而代碼一直沒有警告,今年個(gè)別項(xiàng)目開發(fā)中發(fā)現(xiàn)一些代碼筆誤導(dǎo)致的BUG,而這些問題可以從編譯警告中知道。前幾個(gè)月,領(lǐng)導(dǎo)安排我來(lái)fix這些警告。為了自己,為了后人,不建議使用-w選項(xiàng)。
-Werror
將所有的警告當(dāng)成錯(cuò)誤處理。此選項(xiàng)謹(jǐn)慎建議加上。有的開源庫(kù)警告很多(大名鼎鼎的ffmpeg也有很多警告呢),一一改掉耗時(shí)耗人力,必要性也不大。最后,公司代碼加入了一個(gè)開源庫(kù),里面有很多代碼警告,可能領(lǐng)導(dǎo)又安排我來(lái)fix了。
-Wfatal-errors
遇到第一個(gè)錯(cuò)誤就停止,減少查找錯(cuò)誤時(shí)間。建議加上。很多人遇到錯(cuò)誤,沒有意識(shí)到從第一個(gè)開始排查。不管是編譯錯(cuò)誤,還是程序運(yùn)行出錯(cuò),從最開始的錯(cuò)誤查起,是個(gè)好的做法。
-Wall開啟“所有”的警告。強(qiáng)烈建議加上,并推薦該選項(xiàng)成為共識(shí)。如case語(yǔ)句沒有default處理,有符號(hào)、無(wú)符號(hào)處理,未使用變量(特別是函數(shù)有大量未使用的數(shù)組,占用棧空間,測(cè)試發(fā)現(xiàn),開辟一個(gè)未使用的8MB的數(shù)組,程序有coredump),用%d來(lái)打印地址,或%s打印int值,等,都可以發(fā)出警告。
-Wextra
除-Wall外其它的警告。建議加上。
在GCC編譯時(shí),加上必要的警告選項(xiàng),可以避免很多低級(jí)錯(cuò)誤引發(fā)的問題,我就在實(shí)際工程代碼中遇到用“==”來(lái)賦值,我自己寫的代碼也出現(xiàn)過(guò)把“=”當(dāng)成判斷的。但是,有些錯(cuò)誤卻不是用GCC選項(xiàng)能解決的。比如一般項(xiàng)目都會(huì)自定義調(diào)試信息打印函數(shù),但在處理可變參數(shù)類型時(shí),往往不注意。可參考文章《一個(gè)可變參數(shù)類型檢查的示例》。
二、GCC編譯警告細(xì)化
上面只是大概講幾個(gè)重要的選項(xiàng)。由于GCC的警告選項(xiàng)太多了,下面盡自己能力寫一下。
-Wall選項(xiàng),顧名思義,就是“所有”的意思,它包括:
[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
但不要被它的表面意思迷惑,要不,怎么還會(huì)有-Wextra呢。-Wextra包括(有幾個(gè)選項(xiàng)重復(fù)了,不懂原因):
[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類作為數(shù)組下標(biāo)(因?yàn)閏har可能是有符號(hào)數(shù))
-Wcomment:
注釋使用不規(guī)范。如“/* */”注釋中還包括“/*”。我在項(xiàng)目源碼發(fā)現(xiàn)過(guò),不止一處。
-Wmissing-braces
括號(hào)不匹配。在多維數(shù)組的初始化或賦值中經(jīng)常出現(xiàn)。下面a沒有完整被初始化,b完整初始化:
int a[2][2] = { 0, 1, 2, 3 };
int b[2][2] = { { 0, 1 }, { 2, 3 } };
-Wparentheses
括號(hào)不匹配,在運(yùn)算符操作或if分支語(yǔ)句中,可能會(huì)出現(xiàn)此警告。
如“a&&b||c^d”會(huì)出現(xiàn)警告。下面代碼片段也會(huì)有警告
{
if (a)
if (b)
foo ();
else
bar (); // 這個(gè)else實(shí)際是if (b)的分支,不是if (a),因此,要用括號(hào)來(lái)表明其屬于哪個(gè)分支
}
這類bug隱藏得深,建議顯式地加上括號(hào)。
-Wsequence-point
如出現(xiàn)i=i++這類代碼,則報(bào)警告。-Wall默認(rèn)有該警告
-Wswitch-defaultcase
沒有default時(shí),報(bào)警告
-Wunused-but-set-parameter
設(shè)置了但未使用的參數(shù)警告
-Wunused-but-set-variable
設(shè)置了但未使用的變量警告
-Wunused-function
聲明但未使用函數(shù)
-Wunused-label
未使用的標(biāo)簽,比如用goto會(huì)使用label,但在刪除goto語(yǔ)句時(shí),忘了刪除label。
-Wunused-variable
未使用的變量
-Wmaybe-uninitialized
變量可能沒有被初始化。特別是在有if語(yǔ)句或switch語(yǔ)句中,最好在聲明變量時(shí)加上初始化。
下面代碼片段中,當(dāng)y不是1、2、3時(shí),x沒有明確的值,是不安全的。
{
int x;
switch (y)
{
case 1: x = 1;
break;
case 2: x = 4;
break;
case 3: x = 5;
}
foo (x);
}
-Wfloat-equal
對(duì)浮點(diǎn)數(shù)使用等號(hào),這是不安全的。
{
float d = 2.0;
if (d == i)
{
。。。
}
}
-Wreturn-type
函數(shù)有返回值,但函數(shù)體個(gè)別地方?jīng)]有返回值(特別是有if判斷,可能忘記在else添加返回值)。
int foo()
{
if(a==1)
{
return ok;
}
// no return here
}
-Wpointer-sign
指針有符號(hào)和無(wú)符號(hào)的錯(cuò)誤傳參。如函數(shù)使用unsigned char*,但傳入char*指針。
-Wsign-compare
有符號(hào)和無(wú)符號(hào)比較。
-Wconversion-null
-Wsizeof-pointer-memaccess
在sizeof中經(jīng)常出現(xiàn),下面代碼片段中,this為指針,4字節(jié),無(wú)法保證完整初始化類。
memset(this, 0, sizeof(this));
-Wreorder
C++出現(xiàn),構(gòu)造函數(shù)中成員變量初始化與聲明的順序不一致。
-Woverflow
范圍溢出。
-Wshadow
局部變量覆蓋參數(shù)、全局變量,報(bào)警告
評(píng)論
查看更多