GCC警告选项例解.docx
- 文档编号:28558376
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:17
- 大小:21.57KB
GCC警告选项例解.docx
《GCC警告选项例解.docx》由会员分享,可在线阅读,更多相关《GCC警告选项例解.docx(17页珍藏版)》请在冰豆网上搜索。
GCC警告选项例解
GCC警告选项例解
程序员是追求完美的一族,即使是一般的程序员大多也都不想看到自己的程序中有甚至那么一点点的瑕疵。
遇到任意一条编译器警告都坚决不放过。
有人会说:
我们可以使用比编译器更加严格的静态代码检查工具,如splint。
这个建议也很不错。
不过lint工具使用起来较繁琐,有时候还需要记住一些特定符号并插入到你自己的代码中才行,门槛较高,这也让很多人止步于此。
那么我们就从此放弃么?
不,如今的编译器做得都很好,它可以帮助我们的找到绝大多数可能出现问题的代码,前提是你要学会控制编译器去找到这些问题代码,而熟悉编译器的警告选项恰恰是体现控制力的好方法。
当你可以自如控制编译器警告输出的时候,你就算是'入道'了,同时你对语言的理解也更进一步了。
有人说:
我就是用一个-Wall选项就可以了,一般选手可以这么做,而且他可以不知道-Wall会跟踪哪些类型的问题;但是高级选手是不会只使用-Wall的,他会把每条警告都研究的很透彻,会在Makefile中列出他想让编译器输出哪些类型的警告以替代-Wall,他会屏蔽掉那些对他的代码'毫无用处'的警告(很可能他使用了编译器对语言的扩展功能),他会有个和编译器交流的过程。
俗话说:
'工欲善其事,必先利其器',一直在工作中使用GNUC编译器(以下简称GCC),这里对GCC的一些警告选项细致的分析,并列举几个简单的例子[注1]供分析参考。
1.-Wall集合警告选项
我们平时可能大多数情况只使用-Wall编译警告选项,实际上-Wall选项是一系列警告编译选项的集合。
下面逐一分析这一集合中的各个选项:
[-Wchar-subscripts]
如果数组使用char类型变量做为下标值的话,则发出警告。
因为在某些平台上char可能默认为signedchar,一旦溢出,就可能导致某些意外的结果。
e.g.
/*test_signed_char.c*/
#include
intmain(){
char c =255;//我们以为char是无符号的,其范围应该是[0,255]
int i =0;
int a[256];
for(i=0;i<256;i++){
a[i]=1;
}
printf("%d\n",c);//我们期待输出255
printf("%d\n",a[c]);//我们期待输出1
printf("%d\n",a[255]);
return0;
}
gcc-Wchar-subscriptstest_signed_char.c
test_signed_char.c:
Infunction`main':
test_signed_char.c:
13:
warning:
arraysubscripthas type `char'
其输出结果:
-1
-4197476
1
从输出结果来看Solaris9/gcc3.2上char默认实现类型为signedchar;在WindowsXP/gcc-3.4.2上也是一样。
Windows上的输出结果:
-1
16(随机值)
1
[-Wcomment]
当'/*'出现在'/*...*/'注释中,或者'\'出现在'//...'注释结尾处时,使用-Wcomment会给出警告。
不要小觑这些马虎代码,它很可能会影响程序的运行结果。
如下面的例子:
e.g.
/*
*test_comment.c
*gcc-Wcommenttest_comment.c
*/
#include
intmain(){
int a =1;
int b =2;
int c =0;//okjusttest\
c=a+b;
/*
*这里我们期待c=3
*/*但实际上输出c=0
*/
printf("thecis%d\n",c);
return0;
}
gcc-Wcommenttest_comment.c
test_comment.c:
10:
30:
warning:
multi-linecomment
test_comment.c:
15:
12:
warning:
"/*"withincomment
输出:
thecis0
[-Wformat]
检查printf和scanf等格式化输入输出函数的格式字符串与参数类型的匹配情况,如果发现不匹配则发出警告。
某些时候格式字符串与参数类型的不匹配会导致程序运行错误,所以这是个很有用的警告选项。
e.g.
/*
*test_format.c
*/
#include
intmain(){
long l =1;
doubled =55.67;
printf("%d\n",l);
printf("%d\n",d);
return0;
}
gcc-Wformattest_format.c
test_format.c:
Infunction`main':
test_format.c:
10:
warning:
intformat,longintarg(arg2)
test_format.c:
11:
warning:
intformat,doublearg(arg2)
输出:
1
1078711746
[-Wimplicit]
该警告选项实际上是-Wimplicit-int和-Wimplicit-function-declaration两个警告选项的集合。
前者在声明函数却未指明函数返回类型时给出警告,后者则是在函数声明前调用该函数时给出警告。
e.g.
/*
*test_implicit.c
*/
#include
add(inta,intb){//函数没有声明返回类型
returna+b;
}
inttest(){
int a =0;
int b =0;
int c =0;
int d =0;
c=add(a,b);
d=sub(a,b);//未声明sub的函数原型
return0;
}
gcc-Wimplicit-ctest_implicit.c
test_implicit.c:
7:
warning:
return type defaultsto`int'
test_implicit.c:
Infunction`test':
test_implicit.c:
18:
warning:
implicitdeclarationoffunction`sub'
[-Wmissing-braces]
当聚合类型或者数组变量的初始化表达式没有'充分'用括号{}括起时,给出警告。
文字表述很难理解,举例说明则清晰些。
看下面的例子:
e.g.
/*
*test_missing_braces.c
*/
structpoint{
int x;
int y;
};
structline{
structpointstart;
structpointend;
};
typedefstructlineline;
intmain(){
int array1[2][2] ={11,12,13,14};
int array2[2][2] ={{11,12},{13,14}};//ok
line l1 ={1,1,2,2};
line l2 ={{2,2},{3,3}};//ok
return0;
}
gcc-Wmissing-bracestest_missing_braces.c
test_missing_braces.c:
Infunction`main':
test_missing_braces.c:
19:
warning:
missingbracesaroundinitializer
test_missing_braces.c:
19:
warning:
(nearinitializationfor`array1[0]')
test_missing_braces.c:
21:
warning:
missingbracesaroundinitializer
test_missing_braces.c:
21:
warning:
(nearinitializationfor`l1.start')
[-Wparentheses]
这是一个很有用的警告选项,它能帮助你从那些看起来语法正确但却由于操作符优先级或者代码结构'障眼'而导致错误运行的代码中解脱出来。
好长的一个长句,还是看例子理解吧!
:
)
e.g.
/*
*test_parentheses.c
*gcc-Wparenthesestest_parentheses.c
*/
#include
intmain(){
int a =1;
int b =1;
int c =1;
int d =1;
if(a&&b||c){//人们很难记住逻辑操作符的操作顺序,所以编译器建议加上()
;
}
if(a==12)
if(b)
d=9;
else
d=10;//从代码的缩进上来看,这句仿佛是if(a==12)的else分支
printf("thedis%d\n",d);//期待d=10,而结果却是1
return0;
}
gcc-Wparenthesestest_parentheses.c
test_parentheses.c:
Infunction`main':
test_parentheses.c:
13:
warning:
suggestparenthesesaround&&within||
test_parentheses.c:
17:
warning:
suggestexplicitbracestoavoidambiguous`else'
输出:
thedis1
[-Wsequence-point]
关于顺序点(sequencepoint),在C标准中有解释,不过很晦涩。
我们在平时编码中尽量避免写出与实现相关、受实现影响的代码便是了。
而-Wsequence-point选项恰恰可以帮我们这个忙,它可以帮我们查出这样的代码来,并给出其警告。
e.g.
/*
*test_sequence_point.c
*gcc-Wsequence-pointtest_sequence_point.c
*/
#include
intmain(){
int i=12;
i=i--;
printf("theiis%d\n",i);
return0;
}
gcc-Wsequence-pointtest_sequence_point.c
test_sequence_point.c:
Infunction`main':
test_sequence_point.c:
10:
warning:
operationon`i'maybeundefined
在两个平台上给出的编译警告都是一致的,但是输出结果却大相径庭。
Solaris输出:
theiis11
Windows输出:
theiis12
类似的像这种与顺序点相关的代码例子有:
i=i++;
a[i]=b[i++]
a[i++]=i
等等...
[-Wswitch]
这个选项的功能浅显易懂,通过文字描述也可以清晰的说明。
当以一个枚举类型(enum)作为switch语句的索引时但却没有处理default情况,或者没有处理所有枚举类型定义范围内的情况时,该选项会给处警告。
e.g.
/*
*test_switch1.c
*/
enumweek{
SUNDAY,
MONDAY,
TUESDAY/*onlyanexample,weomittedtheothers*/
};
inttest1(){
enumweek w =SUNDAY;
switch(w){
caseSUNDAY:
break;//withoutdefaultortheothercasehandlings
};
return0;
}
inttest2(){//Ok,won'tinvokeevenawarning
enumweek w =SUNDAY;
switch(w){
caseSUNDAY:
break;
default:
break;
};
return0;
}
inttest3(){//Ok,won'tinvokeevenawarning
enumweek w =SUNDAY;
switch(w){
caseSUNDAY:
break;
caseMONDAY:
break;
caseTUESDAY:
break;
};
return0;
}
gcc-Wswitch-ctest_switch.c
test_switch.c:
Infunction`test1':
test_switch.c:
16:
warning:
enumerationvalue`MONDAY'nothandledinswitch
test_switch.c:
16:
warning:
enumerationvalue`TUESDAY'nothandledinswitch
[-Wunused]
-Wunused是-Wunused-function、-Wunused-label、-Wunused-variable、-Wunused-value选项的集合,-Wunused-parameter需单独使用。
(1)-Wunused-function用来警告存在一个未使用的static函数的定义或者存在一个只声明却未定义的static函数,参见下面例子中的func1和func2;
(2)-Wunused-label用来警告存在一个使用了却未定义或者存在一个定义了却未使用的label,参加下面例子中的func3和func7;
(3)-Wunused-variable用来警告存在一个定义了却未使用的局部变量或者非常量static变量;参见下面例子中func5和var1;
(4)-Wunused-value用来警告一个显式计算表达式的结果未被使用;参见下面例子中func6
(5)-Wunused-parameter用来警告一个函数的参数在函数的实现中并未被用到,参见下面例子中func4。
下面是一个综合的例子
e.g.
/*
*test_unused.c
*/
staticvoidfunc1();//toprovefunctionusedbutneverdefined
staticvoidfunc2();//toprovefunctiondefinedbutnotused
staticvoidfunc3();//toprovelabelusedbutneverdefined
staticvoidfunc7();//toprovelabeldefinedbutneverused
staticvoidfunc4(inta);//toproveparameterdeclaredbutnotused
staticvoidfunc5();//toprovelocalvariabledefinedbutnotused
staticvoidfunc6();//toprovevalueevaluatedbutnotused
staticintvar1;
voidtest(){
func1();
func3();
func4(4);
func5();
func6();
}
staticvoidfunc2(){
;//donothing
}
staticvoidfunc3(){
gotoover;
}
staticvoidfunc4(inta){
;//donothing
}
staticvoidfunc5(){
int a=0;
}
staticvoidfunc6(){
int a=0;
int b=6;
a+b;
}
gcc-Wunused-parameter-ctest_unused.c//如果不是用-Wunused-parameter,则func4函数将不被警告。
test_unused.c:
Infunction`func3':
test_unused.c:
30:
label`over'usedbutnotdefined
test_unused.c:
Infunction`func7':
test_unused.c:
35:
warning:
deprecateduseoflabelatendofcompoundstatement
test_unused.c:
34:
warning:
label`over'definedbutnotused
test_unused.c:
Infunction`func4':
test_unused.c:
37:
warning:
unusedparameter`a'
test_unused.c:
Infunction`func5':
test_unused.c:
42:
warning:
unusedvariable`a'
test_unused.c:
Infunction`func6':
test_unused.c:
48:
warning:
statementwithnoeffect
test_unused.c:
Attoplevel:
test_unused.c:
6:
warning:
`func1'usedbutneverdefined
test_unused.c:
25:
warning:
`func2'definedbutnotused
test_unused.c:
14:
warning:
`var1'definedbutnotused
[-Wuninitialized]
该警告选项用于检查一个局部自动变量在使用之前是否已经初始化了或者在一个longjmp调用可能修改一个non-volatileautomaticvariable时给出警告。
目前编译器还不是那么smart,所以对有些可以正确按照程序员的意思运行的代码还是给出警告。
而且该警告选项需要和'-O'选项一起使用,否则你得不到任何uinitialized的警告。
e.g.
/*
*test_uninitialized.c
*/
inttest(inty){
int x;
switch(y){
case1:
x=11;
break;
case2:
x=22;
break;
case3:
x=33;
break;
}
return
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- GCC 警告 选项