用编译选项帮你挑错

/一觉亮天

 

由于C语言的灵活和设计上的追求高效率,在写C程序的时候,经常会语法正确,但隐含逻辑错误。比如变量未初始化,switch语句没有default分支等。一些编译要求严格的语言,这种情况在编译阶段会报错或报告警,但C语言编译器却视而不见。


PC-Lint就是可以检查类似错误的工具,可以认为PC-Lint是更严格的C编译器。实际上如果我们懂得运用C语言编译器的编译选项,也可以一定程度上发现隐含的逻辑错误。下面我们以gcc编译器为例,在Redhat Enterprise Linux5.3上测试看如何让gcc编译器发现隐含未初始化变量。

 

如下面的程序:

 

//code_begin //gcc_flags.c #include <stdio.h> int tst_uninitialized1(int input); int tst_uninitialized2(int input); int main(){ tst_uninitialized1(3); tst_uninitialized2(3); return 0; } int tst_uninitialized1(int input){ int ui; if(input %2 ==0){ ui = input; } return ui; } int tst_uninitialized2(int input){ int ui; if(input %2 ==0){ ui = input; }else{ ui = input+input; } return ui; } //code_end

 

通常我们编译就用gcc-c gcc_flags.c,这样的话,编译器什么也不说。

 

如果我们加上检查未初始化的变量的选项再试gcc-c -Wuninitialized gcc_flags.c,则gcc会提示-Wuninitialized is notsupported without -O。这告诉我们需要加-O选项,- Wuninitialized选项才会生效。-W是设置Warning的选项。-O是设置Optimization(优化)的选项,有-O-O1-O2等优化级别,我们用O2

 

我们加上优化选项再试gcc-c -Wuninitialized -O2 gcc_flags.c,则gcc会有下面的提示:

 

gcc_flags.c: In function ‘tst_uninitialized1’:

gcc_flags.c:13: warning: ‘ui’ may be used uninitialized inthis f?

 

现在gcc可以发现未被初始化的变量了,而且gcc足够聪明,它会检查语句来推测未被初始化的变量,而不是武断地下结论。比如在函数tst_uninitialized1tst_uninitialized2中,最初我们都声明了一个未赋初值的变量ui,但gcc只会认为tst_uninitialized1中的ui可能未被初始化,而不会认为函数tst_uninitialized2有问题,因为uninitialized2中无论函数执行了if语句的哪个分支,ui都会被初始化。

 

gcc编译器中这样的-W选项很多,比如-Wswitch-default选项会对没有default分支的switch语句告警,比如-Wenum-compare选项会对不同enum类型的变量比较告警,等。为了简单起见,我们可以把这些选项全都加上,用-Wall-Wextra会包含大部分gcc支持的-W选项。更猛一点,我们可以加上-Werror,这样gcc会把warning当做error看待,确保我们一定去掉这些Warning才会编译成功。最后的编译选项如下:

 

gcc -c -Wall -Wextra -Werror -O2 gcc_flags.c

 

 

你可能感兴趣的:(UI,gcc,input,编译器,optimization)