GCC 编译及编译选项

      俗话说:'工欲善其事,必先利其器',一直在工作中使用GNU C编译器(以下简称GCC),这里对GCC的一些警告选项细致的分析,并列举几个简单的例子[注1]供分析参考。

1、 -Wall集合警告选项我们平时可能大多数情况只使用-Wall编译警告选项,实际上-Wall选项是一系列警告编译选项的集合。下面逐一分析这一集合中的各个选项:

1.1 [-Wchar-subscripts]

[-Wchar-subscripts]如果数组使用char类型变量做为下标值的话,则发出警告。因为在某些平台上char可能默认为signed char,一旦溢出,就可能导致某些意外的结果。

/* test_signed_char.c */
#include<stdio.h>

int main () {       
    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]);        
    return 0;
}

gcc -Wchar-subscripts test_signed_char.ctest_signed_char.c: In function `main':test_signed_char.c:13: warning: array subscript has type `char'

其输出结果:-1-41974761从输出结果来看Solaris 9/gcc 3.2上char默认实现类型为signed char;在Windows XP/gcc-3.4.2上也是一样。Windows上的输出结果:-116 (随机值)1

1.2 [-Wcomment]

[-Wcomment]当'/*'出现在 '/* ... */'注释中,或者'\'出现在'// ...'注释结尾处时,使用-Wcomment会给出警告。不要小觑这些马虎代码,它很可能会影响程序的运行结果。如下面的例子:

/* test_comment.c * gcc -Wcomment test_comment.c */
#include<stdio.h>

int main() {
    int     a       = 1; 
    int     b       = 2;        
    int     c       = 0; // ok just test\        
    c = a + b;  
    /*  这里我们期待c = 3  但实际上输出c = 0  */        
    
    printf("the c is %d\n", c);       

    return 0;
}

gcc -Wcomment test_comment.ctest_comment.c:10:30: warning: multi-line commenttest_comment.c:15:12: warning: "/*" within comment

输出:the c is 0

1.3 [-Wformat]

[-Wformat]检查printf和scanf等格式化输入输出函数的格式字符串与参数类型的匹配情况,如果发现不匹配则发出警告。某些时候格式字符串与参数类型的不匹配会导致程序运行错误,所以这是个很有用的警告选项。

/* test_format.c */
#include<stdio.h>

int main() {       
    long    l       = 1;        
    double  d       = 55.67;
     
    printf("%d\n", l);        
    printf("%d\n", d);        

    return 0;
}

gcc -Wformat test_format.ctest_format.c: In function `main':test_format.c:10: warning: int format, long int arg (arg 2)test_format.c:11: warning: int format, double arg (arg 2)

输出:11078711746

1.4 [-Wimplicit]

[-Wimplicit]该警告选项实际上是-Wimplicit-int和-Wimplicit-function-declaration两个警告选项的集合。前者在声明函数却未指明函数返回类型时给出警告,后者则是在函数声明前调用该函数时给出警告。

/* test_implicit.c */
#include<stdio.h>

add(int a, int b) { //函数没有声明返回类型       
     return a + b;
}


int test() {        

    int     a       = 0;       
    int     b       = 0;       
    int     c       = 0;       
    int     d       = 0;
    
    c = add(a, b);        
    d = sub(a, b); //未声明sub的函数原型        

    return 0;
}

gcc -Wimplicit -c test_implicit.ctest_implicit.c:7: warning: return type defaults to `int'test_implicit.c: In function `test':test_implicit.c:18: warning: implicit declaration of function `sub'

1.5 [-Wmissing-braces]

[-Wmissing-braces]当聚合类型或者数组变量的初始化表达式没有'充分'用括号{}括起时,给出警告。文字表述很难理解,举例说明则清晰些。看下面的例子:

/*  test_missing_braces.c */
struct point {
        int     x;        
        int     y;
};

struct line {        
        struct point start;
        struct point end;};

typedef struct line line;

int main() {       

     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

      return 0;
}

gcc -Wmissing-braces test_missing_braces.ctest_missing_braces.c: In function `main':test_missing_braces.c:19: warning: missing braces around initializertest_missing_braces.c:19: warning: (near initialization for `array1[0]')test_missing_braces.c:21: warning: missing braces around initializertest_missing_braces.c:21: warning: (near initialization for `l1.start')

1.6 [-Wparentheses]

[-Wparentheses]这是一个很有用的警告选项,它能帮助你从那些看起来语法正确但却由于操作符优先级或者代码结构'障眼'而导致错误运行的代码中解脱出来。好长的一个长句,还是看例子理解吧!:)

/* test_parentheses.c * gcc -Wparentheses  test_parentheses.c */
#include<stdio.h>


int main() {       

     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("the d is %d\n", d); //期待d = 10, 而结果却是1        
     return 0;
}

gcc -Wparentheses test_parentheses.ctest_parentheses.c: In function `main':test_parentheses.c:13: warning: suggest parentheses around && within ||test_parentheses.c:17: warning: suggest explicit braces to avoid ambiguous `else'

输出:the d is 1

1.7 [-Wsequence-point]

[-Wsequence-point]关于顺序点(sequence point),在C标准中有解释,不过很晦涩。我们在平时编码中尽量避免写出与实现相关、受实现影响的代码便是了。而-Wsequence-point选项恰恰可以帮我们这个忙,它可以帮我们查出这样的代码来,并给出其警告。

/* test_sequence_point.c * gcc -Wsequence-point test_sequence_point.c */

#include<stdio.h>

int main() {        
    int     i = 12;        
    i = i--;        
    printf("the i is %d\n", i);        
    return 0;
}

gcc -Wsequence-point test_sequence_point.ctest_sequence_point.c: In function `main':test_sequence_point.c:10: warning: operation on `i' may be undefined

在两个平台上给出的编译警告都是一致的,但是输出结果却大相径庭。

Solaris输出:the i is 11

Windows输出:the i is 12

类似的像这种与顺序点相关的代码例子有:i = i++;a[i] = b[i++] a[i++] = i等等...

1.7 [-Wswitch]

[-Wswitch]这个选项的功能浅显易懂,通过文字描述也可以清晰的说明。当以一个枚举类型(enum)作为switch语句的索引时但却没有处理default情况,或者没有处理所有枚举类型定义范围内的情况时,该选项会给处警告。

/* test_switch1.c */
enum week {   
    SUNDAY,       
    MONDAY,        
    TUESDAY /* only an example , we omitted the others */
};

int test1() {        
    enum week       w       = SUNDAY;
    switch(w) {                
        case SUNDAY:                        
            break; // without default or the other case handlings        };

        return 0;
}

int test2() { // Ok, won't invoke even a warning        
    enum week       w       = SUNDAY;        
    switch(w) {                
        case SUNDAY:                        
            break;                
        default:                        
            break;                        
    };

     return 0;
}

int test3() { // Ok, won't invoke even a warning        
    enum week       w       = SUNDAY;        
    switch(w) {                
        case SUNDAY:                        
            break;                
  • 7
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值