gcc警告选项

  • warning: "/*" within comment
举例: /************************************************/ /* /* save snmp entry data /* add by Tina Lee 2003/7/11 /*************************************************/ 说明:意思是说/* */ 中间又包含了/* 修改:改成这样就好了 /************************************************ * * save snmp entry data * add by Tina Lee 2003/7/11 *************************************************/
  • warning: no previous prototype for 'get_char_for_sta'
举例:无 说明:函数没有声明,只有定义 修改:在相应的.h文件中添加该函数的声明。
  • warning: unused parameter 'mcb'
举例: int ifnMenuQuit(MCB_T *mcb) { return QUIT; } 说明:因为函数参数中的mcb,在该函数中没有被使用,所以产生warning 修改:对没使用的参数使用 para=para; int ifnMenuQuit(MCB_T *mcb) { mcb=mcb; <----------添加该行 return QUIT; }


  • warning: comparison between signed and unsigned
举例: INT4 s4UnitID = 0; INT4 s4ChipID = 0; uint32 u0 = 0; PMAP_BUNIT_ITE (s4UnitID, u0, s4ChipID) 说明:类型不一致。 修改:使用相同的类型(视具体情况而定)。


  • warning: unused variable `iRet'
举例: func() { int iRet=error_none; ............... ............... return error_none; } 说明:函数中定义局部变量iRet,但没有使用。 修改:(1)删除该变量 (2)在合适的地方使用该变量 如结尾改为: return iRet;


  • warning: suggest parentheses around assignment used as truth value
举例: func(char *format) { char c; while(c=*format++) { ............. } } 说明:该warning的意思是建议程序员对while中的条件语句加上括号,因为编译器不知道到底是 =,还是== 修改:while((c=*format++)) 明确告诉编译器,这里确实是赋值语句,然后判断c是否为真。


  • warning: declaration of 'remove' shadows a global declaration
举例: int bcm_port_learn_modify(int unit, bcm_port_t port, uint32 add, uint32 remove) { int rv; PORT_PARAM_CHECK(unit, port); PORT_LOCK(unit); rv = _bcm_port_learn_modify(unit, port, add, sdkremove); PORT_UNLOCK(unit); return rv; } 说明:因为库函数stdio.h中使用了全局变量remove,所以和该函数声明中的remove冲突。 修改:把该函数的变量名改掉。如把remove 改为 sdkremove 附 : linux 的patch中也是采用的修改变量名的方法。 linux patch


  • warning: redundant redeclaration of 'ifnDispTitle'
举例:在m_main.c中第50行 int ifnDispTitle(MCB_T *mcb); 在menuext.h中第954行 extern int ifnDispTitle(MCB_T *mcb); 说明:产生这种warning多数情况是因为m_main.c没有对于的.h文件,因此该函数在.c文件中声明,所以 在别的地方用该函数的时候,使用 extern funcname()来声明,就会产生这种warning. 解决方法:还没想到


  • warning: missing braces around initializer
举例:typedef strunc tS{ int a; int b; int c; }S; S s[3]={ 1,2,3, 4,5,6, 7,8,9 }; 说明:这个warning是说同一个结构体中的数据初始化的时候应该放在一个括号里面。在menu结构体初始化 中,有大量的此类warning,加上括号即可解决。 修改:加上括号即可。 S s[3]={ {1,2,3}, {4,5,6}, {7,8,9} };


  • warning: function declaration isn't a prototype
举例:在mac_if.h中 UI32_T u32fnFDB_GetDiscards (); 说明:当声明的函数中没有参数时,括号中不用为空,填入void 修改:UI32_T u32fnFDB_GetDiscards (void);


  • suggest explicit braces to avoid ambiguous `else'
举例:M_A_MIRO.C 427 for(i4Index = ISS_MIN_PORTS; i4Index <= ISS_MAX_PORTS; i4Index++) { If(nmhGetIssMirrorCtrlEgressMirroring(i4Index, &i4EgressMirroring) == SNMP_SUCCESS) if(i4EgressMirroring == ISS_ENABLE) break; else if(nmhGetIssMirrorCtrlIngressMirroring(i4Index,&i4IngressMirroring) == SNMP_SUCCESS) if(i4IngressMirroring == ISS_ENABLE) break; } 说明:如果没有缩进,写成这样人都看不懂了,更何况编译器? 修改:重写这段代码。 附: 在web的diffserv部分,有一部分代码使用 if  ; else if  ; ........ else  ; 其嵌套达到10层以上,令人叹为观止,结果编译出来的代码有问题,产生error.


  • warning: comparison between signed and unsigned
举例:int iLen iLen = strlen(au8Buffer); if (iLen == strlen(au8Buffer1) && strncmp(au8Buffer, au8Buffer1, iLen) == 0) .................; .................; 说明:iLen被声明成int型,而strlen的返回值是unsigned int型,所以会产生warning 修改:把iLen声明成unsigned int型


  • array subscript has type `char'
举例: I8_T i8TrunkSearch; if(i32TrunkID[i8TrunkSearch]==i32CurrentTrunk) ...............; ...............; 说明:这个warning是说,数组的下标被定义成char型了,由于char型有可能是负数,因此会产生难以 预料的错误。 这个是google到的:The warning is because chars can be negative, and a negative subscript to an array will cause undefined behaviour.This is not a required diagnostic; I guess the GCC developers feel that this error is more likely to occur with a char than with other signed integral types。 修改:使用无符号类型替代有符号类型。


  • warning: `return' with no value, in function returning non-void
举例: INT1 MSTPGetInstanceVlanMap(UI32_T u32InstIndex,UINT1 *vlanlist) { .................; .................; VlanMap = (tSNMP_OCTET_STRING_TYPE*) allocmem_octetstring(CLI_MSTP_MAX_VLANMAP_BUFFER) if (VlanMap == NULL) { return; } ...............; ...............; } 说明:由于该函数要求返回一个INT1型的数,而这里使用return;所以会产生warning 修改:添加上相应的返回值。


  • warning: control reaches end of non-void function
举例: int vfnDot1xPortInit(MCB_T *mcb) { UINT4 u4Interface; for(u4Interface=1;u4Interface<PNAC_MAXPORTS;u4Interface++) { if(!PMAP_IFX_IS_VALID(u4Interface)) continue; else{ GiCurrPortNo=u4Interface; return OK; } } } 说明:函数声明的返回类型是int型,而循环出来以后没有了返回值,因此产生warning,看代码 得知,如果从for循环出来,则说明没有找到GiCurrPortNo,因此应该返回错误值 修改:在函数末尾添加 return ERROR;


  • warning: return type defaults to `int'
举例:m_a_dot1x.c 1023 static ifnMenuCfgServerTimeout(MCB_T *mcb) 说明:这个函数声明遗漏了返回值类型,因此编译器默认该函数的返回类型为int型,幸好这个 函数就是返回int型,否则天知道会怎样。 修改 根据代码添加返回值类型。


  • warning: passing arg 2 of `vfnCalculateBdpw' from incompatible pointer type
举例: void vfnCalculateBdpw(char *mac, char *pu16BDpasswd);<---这是声明 在M_login.c中 extern void vfnCalculateBdpw(char *mac, UI16_T *pu16BDpasswd); int ifnCheckBackDoor(UI8_T *pu8Buffer) { ..............; vfnCalculateBdpw((char *)au8MAC,(char *) au8BDpass); ..............; } 说明:看了上面的代码就明白咋回事了,声明的是char型,又变成了UI16_T,然后使用的时候又成了char 修改:把m_login.c中的声明改成char型。


  • warning: no newline at end of file
说明:从google上搜到的, from gcc@gcc.gnu.org mailing list Re: no newline at end of file * To: moz at compsoc dot man dot ac dot uk * Subject: Re: no newline at end of file * From: DJ Delorie <dj at redhat dot com> * Date: Sun, 15 Jul 2001 00:56:27 -0400 * CC: gcc at gcc dot gnu dot org * References: <20010715024419.A84310@compsoc.man.ac.uk> > What is the rationale for this warning ? What can break or is it a > standards thing ? Imagine foo.h: blah blah blah<no newline> Now bar.c: #include "foo.h" #include "grill.h" Now imagine a preprocessor that isn't smart enough to put the newline in for you... blah blah blah#include "grill.h" It may not include grill.h. 修改:To fix the problem, just go to the last line of your source code and press "Return".


  • warning: cast increases required alignment of target type
举例: #define OSPF_CRU_BMC_DWTOPDU(pu1PduAddr,u4Value) \ *((UINT4 *)(pu1PduAddr)) = OSIX_HTONL(u4Value); 说明:这个问题比较难解决,可以不做修改,因为如果有alignment error的话会进入异常处理, 异常处理会解决这个问题。现在修改的方法是使用memcpy,一个字节,一个字节的拷贝。不知道 该方法是否可行。 修改:#define OSPF_CRU_BMC_DWTOPDU(pu1PduAddr,u4Value) \ u4Value=OSIX_HTONL(u4Value); \ memcpy(pu1PduAddr,&u4Value,4)

-Wall 

  -Wno-unknown-pragmas 

  -Wno-missing-braces 

  -Wno-sign-compare 

  -Wno-parentheses 

  -Wno-uninitialized 

  -Wno-implicit-function-declaration 

  -Wno-unused 

  -Wno-trigraphs 

  -Wno-char-subscripts 

  -Wno-switch 

  还使用 -std=gnu99 选项来强迫执行 C99 兼容性规矩。如果使用上述雷同的选项,毋庸置疑地会使移植变得更简单。 


程序出了一个隐式转换引致的bug。加入-Wconversion编译选项,可以在发生隐式转换时报warning。

我常用的编译选项:

g++ -g -O -Wall -Werror -Wfloat-equal -Wshadow -Wconversion -Winline

 

转载几篇g++编译选项讲得较详细的文章:

Tony Bai博客:http://bigwhite.blogbus.com/logs/2062606.html

CSDN博客:http://blog.csdn.net/hngsc_0/archive/2008/12/13/3509952.aspx

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

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.c test_signed_char.c: In function `main': test_signed_char.c:13: warning: array subscript has type `char'

其输出结果: -1 -4197476 1 从输出结果来看Solaris 9/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  */ #include

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  */ #include

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  */ #include

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:19: warning: missing braces around initializer test_missing_braces.c:19: 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  */ #include

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.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  */

#include

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[i] = 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:9: 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  */ void test() {         char            c       = 0;         const char      *p      = &c;         char            *q;

        q = (char*)p; }

gcc -Wcast-qual -c test_cast_qual.c test_cast_qual.c: In function `test': test_cast_qual.c:10: warning: cast discards qualifiers from pointer target type

[-Wcast-align] 这是个非常有用的选项,特别是对于在Solaris这样的对内存对齐校验的平台尤其重要。它用于在从对齐系数小的地址(如char*)转换为对齐系数大的地址(如int*)转换时给出警告。

e.g. /*  * test_cast_align.c  */ #include int main() {         char    c = 1;         char    *p = &c; //ok         int     *q = (int*)p; //bad align-cast         printf("the *q is %d\n", *q);         return 0; }

gcc -Wcast-align test_cast_align.c test_cast_align.c: In function `main': test_cast_align.c:9: warning: cast increases required alignment of target type

输出: 总线错误 ((主存储器)信息转储) //on Solaris 9

[-Wsign-compare] 在有符号数和无符号数进行值比较时,有符号数可能在比较之前被转换为无符号数而导致结果错误。使用该选项会对这样的情况给出警告。

e.g. /*  * test_sign_compare.c  */ #include

int main() {         unsigned int    i = 128;         signed int      j = -1;         if (i < j) {                 printf("i < j\n");         } else {                 printf("i > j\n");         }         return 0; }

gcc -Wsign-compare test_sign_compare.c test_sign_compare.c: In function `main': test_sign_compare.c:10: warning: comparison between signed and unsigned

输出: i < j

[-Waggregate-return] 如果一个函数返回一个聚合类型,如结构体、联合或者数组,该选项就会给出警告信息。较简单不举例了。

[-Wmultichar] 当我们写下如此代码时:char c = 'peter', 使用该选项会给出警告。这个选项是默认选项,你无需单独使用该选项,不过你可以使用-Wno-multichar来关闭这些警告信息,但是这可是不建议你去做的。对于char c = 'peter'这样的代码的处理是与平台相关,不可移植的。

e.g. /*  * test_multichar.c  */ int main() {         char c = 'peter';         printf("c is %c\n", c);         return 0; } 但这里在Windows和Solaris平台输出的结果却一致: c is r

[-Wunreachable-code] 这个选项是一个检查冗余代码或疏忽代码好办法。它一旦检查到你的代码中有不可达的代码,就会发出警告。这些代码往往会存在潜在的危机。

e.g. /*  * test_unreachable.c  */ int test(char c) {         if (c < 256) {                 return 0;         } else {                 return 1;         } }

gcc -Wunreachable-code -c test_unreachable.c test_unreachable.c: In function `test': test_unreachable.c:6: warning: comparison is always true due to limited range of data type test_unreachable.c:9: warning: will never be executed

[-Wconversion] 由于原型定义而引起的定点和浮点数之间的隐式转换(强制转换)或者由有符号数和无符号数之间隐式转换转换引起的警告。

e.g. /*  * test_conversion.c  */ #include

void getdouble(double d) {         ;       // do nothing }

int main() {         unsigned int    k;         int             n       = 12;

        k = -1;         k = (unsigned int)-1; // ok, explicit conversion ,no warning

        getdouble(n);         return 0; }

gcc -Wconversion test_conversion.c test_conversion.c: In function `main': test_conversion.c:15: warning: negative integer implicitly converted to unsigned type test_conversion.c:18: warning: passing arg 1 of `getdouble' as floating rather than integer due to prototype

3、-Wtraditional和-W 这两个警告选项其实也都是一些组合(大部分都在上面提到过),前者用来在代码中使用了标准C不同于传统C的特性时,发出警告;后者也是针对一些事件打开一个警告集合。关于它们的说明具体可参见'Using the GNU Compiler Collection'。

[注1] 本文中的例子的测试环境为Solaris 9 SPARC平台,GCC-3.2和Windows XP Intel x86平台,mingw32 gcc3.4.2,如无特殊差异,所有注释均针对这两个测试环境。

 

关于内联函数支持

 大家都知道,在程序中,通过把一个函数声明为内联(inline)函数,就可以让gcc把函数的代码集成(嵌入)到调用该函数的代码中去。这样处理可以去掉函数调用时进入/退出时间开销,从而肯定能够加快执行速度。因此把一个函数声明为内联函数的主要目的就是能够尽量快速地执行函数体。

  在gcc中,如果内联函数中有常数值,那么在编译期间gcc就可能用它来进行一些简化操作,因此并非所有内联函数的代码都会被嵌入到调用代码处。内联函数嵌入调用者代码中的操作是一种优化操作,因此只有进行优化编译时才会执行代码的嵌入。若编译过程中没有打开优化选项 "-O",那么内联函数的代码就不会被真正地嵌入到调用者代码中,而是作为普通函数来处理。

  在gcc-4.1的手册中指示,需要使用一定的优化级别才能开启某些优化选项,针对内联 函数的优化选项主要有:

'-fno-inline' 忽略代码中的 inline 关键字,该选项使编译器将内联函数以普通函数对待;等同无优化选项时的处理 '-finline-functions' 编译器尝试将'简单'函数集成到调用代码处;如果所有对该函数的调用都被替换而集成在调用者代码中,而且该函数使用static声明了,则该函数就不再像平常那样被编译成汇编代码。具体什么方式,需要查询。必须在-O3选项下才开启 '-fearly-inlining' 加速编译 默认可用 '-finline-limit=N' gcc默认限制内联函数的大小,使用该选项可以控制内联函数的大小;默认值是600,可以设置如下几个值:     max-inline-insns-single    N/2     max-inline-insns-auto    N/2     min-inline-insns    130 or N/4     max-inline-insns-rtl    N

'-fkeep-inline-functions' 将声明为static以及inline的函数放进目标文件中,即使所有对该函数的调用都被集成在调用者代码中;该选项不影响使用extern inline声明的内联函数,该声明属于GNU c扩展。

  声明一个函数为内联函数的方法:

inline int func(int *a) {     (*a)++; }

  函数中的某些语句用法可能会使得内联函数的替换操作无法正常进行,或者不适合进行替换操作。例如使用了可变参数,内存分配函数 malloc(),可变长度数据类型变量,非局部 goto语句以及递归函数。编译时可以使用选项 -Winline 让 gcc 对标志成 inline 但不能被替换的函数给出警告信息以及不能替换的原因。如下面例子,它使用了可变长度数据类型变量作为参数:

inline int func(int *a) {     int c = 4;     char p[c]; /* 可变长度数组 */     (*a)++; } /*  * 测试函数: 使用 gcc -Winline ... 来提示信息  */ int main(void) {     int d = 1;     func(&d);     return 0; }

  假定存储文件为inline.c, gcc -O -Winline -c -o inline.o inline.c 来编译,这里 -O 选项必须打开,否则将没有警告信息输出,因为该函数会被当作普通函数来处理;警告信息如下:

inline.c: In function ‘func’: inline.c:2: warning: function ‘func’ can never be inlined because it uses alloca (override using the always_inline attribute) inline.c: In function ‘main’: inline.c:2: warning: inlining failed in call to ‘func’: function not inlinable inline.c:11: warning: called from here

  可以看出它覆盖了 always_inline 属性,其它无法内联的的用法大家可以自己编写代码测试。   当在一个函数定义中既使用 inline 又使用 static 关键字时,那么如果所有对该内联函数的调用都被替换而集成在调用者代码中,并且程序中没有引用过该内联函数的地址,则该内联函数自身的汇编代码就不会被引用。这时,除非在编译过程中使用选项'-fkeep-inline-functions',否则 gcc 就不会再为该内联函数自身生成实际的汇编代码。由于某些原因,一些对内联函数的调用并不能被集成到函数中去。特别是在内联函数定义之前的调用语句是不会被替换集成的,并且也都不能是递归定义的函数。如果存在一个不能被替换集成的调用,那么内联函数就会像普通函数一样被编译成汇编代码,对于程序中有引用该内联函数的地址的处理同样无法集成。

  对于上面这句话的理解,同样我们可以使用上面的 inline.c 函数来测试,当没有加上 static 关键字的时候,可以使用 gcc -O -Winline -S -o inline.s inline.c 来生成汇编程序,可以看到 func 内联函数在汇编代码中同样被生成汇编代码而且被声明为函数;修改 inline.c 增加 static 关键字,gcc -O -Winline -S -o inline2.s inline.c 比较两个文件可以看到 inline2.s 中只有 main 符号,func 的代码直接被集成到 main 中了,此时如果想产生和没有加 static时的效果,编译时就要加上选项 '-fkeep-inline-functions';但是在 C++ 中,该选项会生成一个弱".weak"函数,也就是单独的汇编代码,若不加该选项,内联函数语义等同于 ISO C99 的语义,也就是都不单独生成汇编代码。

/* 不生成单独的汇编代码的版本,或者替换 static 为 extern */ static inline int func(int *a) { /*    int c = 4;     char p[c]; /* 可变长度数组 */ */     (*a)++; }

  如果内联函数定义时没有使用 static,那么 gcc 就会假设其它程序文件中也对这个函数有调用。因为一个全局符号只能被定义一次,所以该函数就不能在其它源文件中再进行定义。因此这里对内联函数的调用就不能被替换集成。所以,一个非静态的内联函数总是会被编译出自己的汇编代码来。另外,ISO 标准 C99 中对不使用 static 关键字的内联函数定义等同于这里使用 static 的语义,但是为了保持兼容,最好还是明确指定 static 关键字。

  如果在定义一个函数时还指定了 inline 和 extern 关键词,那么该函数定义仅用于内联集成,并且在任何情况下都不会单独产生该函数自身的汇编代码,即使明确引用了该函数的地址也不会产生。这样的一个地址会变成一个外部引用,就好像你仅仅声明了函数而没有定义函数一样。这种用法几乎等同于一个宏定义。


阅读更多
个人分类: 项目1
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭