zoukankan      html  css  js  c++  java
  • GCC编译器警告命令

    程序员是追求完美的一族,即使是一般的程序员大多也都不想看到自己的程序中有甚至那么一点点的瑕疵。遇到任意一条编译器警告都坚决不放过。有人会说:我们可以使用比编译器更加严格的静态代码检查工具,如
    splint

    这个建议也很不错。不过lint工具使用起来较繁琐,有时候还需要记住一些特定符号并插入到你自己的代码中才行,门槛较高,这也让很多人止步于此。那么我
    们就从此放弃么?不,如今的编译器做得都很好,它可以帮助我们的找到绝大多数可能出现问题的代码,前提是你要学会控制编译器去找到这些问题代码,而熟悉编
    译器的警告选项恰恰是体现控制力的好方法。当你可以自如控制编译器警告输出的时候,你就算是’入道’了,同时你对语言的理解也更进一步了。
    有人说:我就是用一个-Wall选项就可以了,一般选手可以这么做,而且他可以不知道-Wall会跟踪哪些类型的问题;但是高级选手是不会只使用-
    Wall的,他会把每条警告都研究的很透彻,会在Makefile中列出他想让编译器输出哪些类型的警告以替代-Wall,他会屏蔽掉那些对他的代码’毫
    无用处’的警告(很可能他使用了编译器对语言的扩展功能),他会有个和编译器交流的过程。
    俗话说:’工欲善其事,必先利其器’,一直在工作中使用
    GNU
    C

    编译器(以下简称GCC),这里对GCC的一些警告选项细致的分析,并列举几个简单的例子[注1]供分析参考。
    1.
    -Wall集合警告选项
    我们平时可能大多数情况只使用-Wall编译警告选项,实际上-Wall选项是一系列警告编译选项的集合。下面逐一分析这一集合中的各个选项:
    [-Wchar-subscripts]
    如果数组使用char类型变量做为下标值的话,则发出警告。因为在某些平台上char可能默认为signed
    char,一旦溢出,就可能导致某些意外的结果。
    e.g.
    /* test_signed_char.c */
    #i nclude
    int
    main () {
             char     c        = 255; //
    我们以为char是无符号的,其范围应该是[0,255]
             int      i        = 0;
             int 
        a[256];
             for (i = 0; i type
    `char’
    其输出结果:
    -1
    -41Array7476
    1
    从输出结果来看Solaris Array/gcc
    3.2上char默认实现类型为signed char;在Windows
    XP/gcc-3.4.2上也是一样。
    Windows上的输出结果:
    -1
    16
    (随机值)
    1
    [-Wcomment]
    当’/*’出现在 ’/* ... */’注释中,或者’\’出现在’//
    ...’注释结尾处时,使用-Wcomment会给出警告。不要小觑这些马虎代码,它很可能会影响程序的运行结果。如下面的例子:
    e.g.
    /*
    *
    test_comment.c
    * gcc -Wcomment test_comment.c
    */
    #i nclude
    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.c
    test_comment.c:10:30: warning:
    multi-line comment
    test_comment.c:15:12: warning: "/*" within
    comment
    输出:
    the c is
    0
    [-Wformat]
    检查printf和scanf等格式化输入输出函数的格式字符串与参数类型的匹配情况,如果发现不匹配则发出警告。某些时候格式字符串与参数类型的不匹配会导致程序运行错误,所以这是个很有用的警告选项。
    e.g.
    /*
    *
    test_format.c
    */
    #i nclude
    int main() {
             long     l    
       = 1;
             double d        = 55.67;
             printf("%d\n", l);
     
           printf("%d\n", d);
             return 0;
    }
    gcc -Wformat
    test_format.c
    test_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)
    输出:
    1
    1078711746
    [-Wimplicit]
    该警告选项实际上是-Wimplicit-int和-Wimplicit-function-declaration两个警告选项的集合。前者在声明函数却未指明函数返回类型时给出警告,后者则是在函数声明前调用该函数时给出警告。
    e.g.
    /*
    *
    test_implicit.c
    */
    #i nclude
    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.c
    test_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’
    [-Wmissing-braces]
    当聚合类型或者数组变量的初始化表达式没有’充分’用括号{}括起时,给出警告。文字表述很难理解,举例说明则清晰些。看下面的例子:
    e.g.
    /*
    *
    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.c
    test_missing_braces.c: In function
    `main’:
    test_missing_braces.c:1Array: warning: missing braces around
    initializer
    test_missing_braces.c:1Array: warning: (near initialization for
    `array1[0]’)
    test_missing_braces.c:21: warning: missing braces around
    initializer
    test_missing_braces.c:21: warning: (near initialization for
    `l1.start’)
    [-Wparentheses]
    这是一个很有用的警告选项,它能帮助你从那些看起来语法正确但却由于操作符优先级或者代码结构’障眼’而导致错误运行的代码中解脱出来。好长的一个长句,还是看例子理解吧!:)
    e.g.
    /*
    *
    test_parentheses.c
    * gcc -Wparentheses test_parentheses.c
    */
    #i nclude

    int main() {
             int      a        = 1;
             int      b    
       = 1;
             int      c        = 1;
             int      d        =
    1;
             if (a && b || c) { // 人们很难记住逻辑操作符的操作顺序,所以编译器建议加上()
     
                   ;
             }
             if (a == 12)
                     if
    (b)
                             d = Array;
             else
                 
       d = 10; //从代码的缩进上来看,这句仿佛是if (a == 12)的else分支
             printf("the d is
    %d\n", d); //期待d = 10, 而结果却是1
             return 0;
    }
    gcc -Wparentheses
    test_parentheses.c
    test_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
    [-Wsequence-point]
    关于顺序点(sequence
    point),在C标准中有解释,不过很晦涩。我们在平时编码中尽量避免写出与实现相关、受实现影响的代码便是了。而-Wsequence-point选项恰恰可以帮我们这个忙,它可以帮我们查出这样的代码来,并给出其警告。
    e.g.
    /*
    *
    test_sequence_point.c
    * gcc -Wsequence-point
    test_sequence_point.c
    */
    #i nclude
    int main() {
             int      i
    = 12;
             i = i--;
             printf("the i is %d\n", i);
           
     return 0;
    }
    gcc -Wsequence-point
    test_sequence_point.c
    test_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 =
    b[i++]
    a[i++] =
    i
    等等...
    [-Wswitch]
    这个选项的功能浅显易懂,通过文字描述也可以清晰的说明。当以一个枚举类型(enum)作为switch语句的索引时但却没有处理default情况,或者没有处理所有枚举类型定义范围内的情况时,该选项会给处警告。
    e.g.
    /*
    *
    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;
                     case MONDAY:
     
                           break;
                     case TUESDAY:
                 
               break;            
             };
             return 0;
    }
    gcc
    -Wswitch -c test_switch.c
    test_switch.c: In function
    `test1’:
    test_switch.c:16: warning: enumeration value `MONDAY’ not handled in
    switch
    test_switch.c:16: warning: enumeration value `TUESDAY’ not handled in
    switch
    [-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
    */
    static void func1(); //to prove function used but never
    defined
    static void func2(); //to prove function defined but not
    used
    static void func3(); //to prove label used but never defined
    static
    void func7(); //to prove label defined but never used
    static void func4(int
    a); //to prove parameter declared but not used
    static void func5(); //to
    prove local variable defined but not used
    static void func6(); //to prove
    value evaluated but not used
    static int var1;
    void test() {
           
     func1();
             func3();
             func4(4);
             func5();
     
           func6();
    }
    static void func2() {
             ; // do
    nothing
    }
    static void func3() {
             goto over;
    }
    static void
    func4(int a) {
             ; // do nothing
    }
    static void func5() {
        
        int      a = 0;
    }
    static void func6() {
             int      a =
    0;
             int      b = 6;
             a + b;
    }
    gcc -Wunused-parameter
    -c test_unused.c //如果不是用-Wunused-parameter,则func4函数将不被警告。
    test_unused.c: In
    function `func3’:
    test_unused.c:30: label `over’ used but not
    defined
    test_unused.c: In function `func7’:
    test_unused.c:35: warning:
    deprecated use of label at end of compound statement
    test_unused.c:34:
    warning: label `over’ defined but not used
    test_unused.c: In function
    `func4’:
    test_unused.c:37: warning: unused parameter `a’
    test_unused.c: In
    function `func5’:
    test_unused.c:42: warning: unused variable
    `a’
    test_unused.c: In function `func6’:
    test_unused.c:48: warning:
    statement with no effect
    test_unused.c: At top level:
    test_unused.c:6:
    warning: `func1’ used but never defined
    test_unused.c:25: warning: `func2’
    defined but not used
    test_unused.c:14: warning: `var1’ defined but not
    used
    [-Wuninitialized]
    该警告选项用于检查一个局部自动变量在使用之前是否已经初始化了或者在一个longjmp调用可能修改
    一个non-volatile automatic
    variable时给出警告。目前编译器还不是那么smart,所以对有些可以正确按照程序员的意思运行的代码还是给出警告。而且该警告选项需要和’-
    O’选项一起使用,否则你得不到任何uinitialized的警告。
    e.g.
    /*
    *
    test_uninitialized.c
    */
    int test(int y) {
             int      x;
        
        switch (y) {
                     case 1:
                             x =
    11;
                             break;
                     case 2:
              
                  x = 22;
                             break;
                 
       case 3:
                             x = 33;
                            
    break;
             }
             return x;
    }
    gcc -Wuninitialized -O -c
    test_uninitialized.c
    test_uninitialized.c: In function
    `test’:
    test_uninitialized.c:6: warning: `x’ might be used uninitialized in
    this
    function
    2、非-Wall集合警告选项
    以下讨论的这些警告选项并不包含在-Wall中,需要程序员显式添加。
    [-Wfloat-equal]
    该项用来检查浮点值是否出现在相等比较的表达式中。
    e.g.
    /*
    *
    test_float_equal.c
    */
    void test(int i) {
             double d = 1.5;
     
           if (d == i) {
                     ;
             }
    }
    gcc
    -Wfloat-equal -c test_float_equal.c
    test_float_equal.c: In function
    `test’:
    test_float_equal.c:8: warning: comparing floating point with == or !=
    is
    unsafe
    [-Wshadow]
    当局部变量遮蔽(shadow)了参数、全局变量或者是其他局部变量时,该警告选项会给我们以警告信息。
    e.g.
    /*
    *
    test_shadow.c
    */
    int      g;
    void test(int i) {
             short   
    i;
             double g;
    }
    gcc -Wshadow -c test_shadow.c
    test_shadow.c:
    In function `test’:
    test_shadow.c:Array: warning: declaration of `i’ shadows
    a parameter
    test_shadow.c:10: warning: declaration of `g’ shadows a global
    declaration
    test_shadow.c:6: warning: shadowed declaration is
    here
    [-Wbad-function-cast]
    当函数(准确地说应该是函数返回类型)被转换为非匹配类型时,均产生警告。
    e.g.
    /*
    *
    test_bad_func_case.c
    */
    int add(int a, int b) {
             return
    a+b;
    }
    void test() {
             char *p = (char*)add(1, 13);
    }
    gcc
    -Wbad-function-cast -c test_bad_func_case.c
    test_bad_func_case.c: In function
    `test’:
    test_bad_func_case.c:11: warning: cast does not match function
    type
    [-Wcast-qual]
    当去掉修饰源Target的限定词(如const)时,给出警告。
    e.g.
    /*
    *
    test_cast_qual.c

  • 相关阅读:
    容器 list
    迭代器
    排序
    extern "C"
    FZU2127
    HDU1102--最小生成树
    HDU1102(最小生成树Kruskal)
    并查集详解(转自一个很有才的大神)膜拜
    C# switch
    Dijkstra(歪果仁的名字真是长。。。)
  • 原文地址:https://www.cnblogs.com/Skyxj/p/3309398.html
Copyright © 2011-2022 走看看