• C编程常见问题总结


    本文是C编程中一些常见错误的总结,有些是显而易见的,有些则是不容易发现

    本文地址:http://www.cnblogs.com/archimedes/p/get-screwed-c.html,转载请注明源地址。

    1.忘记注释结束符

    代码

    a = b; /* 出现bug
    c = d; /* c = d将不会执行*/

    2.意外的赋值/意外的bool表达式

    代码:

    if(a = b) c;  /*a恒等于b,只有当b!=0的时候才执行*/

    再看下面的代码:

    if(0 < a < 5) c;   /*布尔表达式恒为真*/

    上面代码中的bool表达式恒为真,由于0 < a的值为0或1,永远都小于5成立,当然C中没有bool表达式,这里只是假设

    3.有缺陷的宏

    代码:

    #define assign(a,b) a=(char)b
    assign(x,y>>8)

    变成

    x=(char)y>>8    /* 可能不是你的目的 */ 

    4.不匹配的头文件

    代码:

    //foo.h:
    struct foo { BOOL a};
    //F1.c
    #define BOOL char
    #include "foo.h"
    //F2.c
    #define BOOL int
    #include "foo.h"

    F1与F2对结构体foo中的BOOL类型定义不一致,如果交互就会出现错误

    5.飘忽不定的返回值

    可能你会写下面的代码:

    int foo (a)
    { if (a) return(1); } /* bug,因为有时候没有值返回 */

    6.不可预知的结构体

    看下面的比特包结构:

    struct eeh_type
    {
        uint16 size:          10;   /* 10 bits */
        uint16 code:           6;   /* 6 bits */
    };

    取决于用哪个C编译器,还有你的机器使用大小端,这段代码实现为:

    <10-bits><6-bits> 或 <6-bits><10-bits>

    同时取决于C编译器、机器体系结构、不可思议的优先设置,这些项可能对齐到最近的8, 16, 32, or 64 bits.

    7.不确定的求值顺序

      foo(pointer->member, pointer = &buffer[0]);

    不同的编译器针对函数参数有不同的求值顺序,gcc是从左到右的求值顺序,有的编译器是从右往左

    8.容易改变的块作用域

    代码:

    if( ... ) 
          foo(); 
      else 
          bar();

    当加上调试输出信息:

    if( ... ) 
        foo();          
    else 
        printf( "Calling bar()" );      /* 注意! else止于此 */
        bar();                          /* 注意! bar永远会被执行 */

    9.不安全的返回值

    代码:

    char *f() { 
       char result[80]; 
       sprintf(result,"anything will do"); 
       return(result);    /* 注意! result 被分配在栈上. */ 
     }
    
    int g() 
    { 
       char *p; 
       p = f(); 
       printf("f() returns: %s
    ",p); 
    } 

    10.未定义副作用(side effects

    哪怕一个简单的表达式,C没有定义副作用的顺序,结果取决于你的编译器,i/i++可能等于0或1,看下面的代码:

    #include <stdio .h>
    int foo(int n) {printf("Foo got %d
    ", n); return(0);}
    int bar(int n) {printf("Bar got %d
    ", n); return(0);}
    int main(int argc, char *argv[]) 
    {
        int m = 0;
        int (*(fun_array[3]))();
        int i = 1;
        int ii = i/++i;
        printf("i/++i = %d, ",ii);
        fun_array[1] = foo; fun_array[2] = bar;
        (fun_array[++m])(++m);     
        return 0;
    }

    11.未初始化的局部变量

    事实上这个bug不是那么出名,但是一旦发生严重性不会输给其他的bug,看下面的代码:

    void foo(a)
    { int b;
      if(b) {/* bug! b没有被初始化 */ }
    }

    现代编译器会发出错误的警告,看下面代码:

    void foo(int a) 
    { BYTE *B;
       if(a) B=Malloc(a);
              if(B) { /* BUG! B 可能没被初始化 */ *b=a; } 
    }

    12.杂乱的编译时环境

    编译时环境产生成百上千的编译信息,我们对此知之甚少。有些危险的常用名,导致很难被发现:

    #include <stdio.h>
    #define BUFFSIZE 2048 
    long foo[BUFSIZ];   //注意拼写: BUFSIZ != BUFFSIZE

    编译器不会报错,因为BUFSIZ已经在stdio.h中定义

    13.八进制数

    在C中,八进制数以0开始,如果数字中没有‘8’或‘9’出现,编译器不会警告

     int numbers[] = { 001,        
                               010,        // 8 而不是 10 
                               014  };     // 12, 而不是 14 

    14.有符号字符

    C中的有符号char可能出现各种错误,比如128是一个负数,另外,任何使用低精度整数都必须十分的小心,C使得这些太容易被忽略了

    char s = 127;
    unsigned char u = 127;
    s++;      /* 结果是负数 */
    if (s<u) { /* true!*/ }
    if(s>127) { /* 永不可能为true */  }
    if(u<0) {  /* 永不可能为true*/  }

    15.糟糕的“标准库”

    代码:

    { int a=1,b=2;
      char buf[10];
      scanf("%d %d",a,b);            // &a,&b? 
      sprintf(buf,"this is the result: %d %d"); // 溢出            
    }
  • 相关阅读:
    类型初始值设定项引发异常的解决方法
    sql修改排序规则,区分大小
    SQLServer查询所有子节点
    Cannot resolve the collation conflict between "Chinese_PRC_CI_AS" and "SQL_L及由于排序规则不同导致查询结果为空的问题
    SQLServer跨库查询--分布式查询
    DataTable对象的操作问题
    .Net插入大批量数据
    SQL修改字段类型
    数据抓包分析
    Qss 皮肤
  • 原文地址:https://www.cnblogs.com/wuyudong/p/get-screwed-c.html
Copyright © 2020-2023  润新知