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\n",p); 
} 

10.未定义副作用(side effects

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

#include <stdio .h>
int foo(int n) {printf("Foo got %d\n", n); return(0);}
int bar(int n) {printf("Bar got %d\n", 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"); // 溢出            
}
目录
相关文章
|
4月前
|
存储 SQL 关系型数据库
MySQL数据库学习指南与学习资源推荐
MySQL数据库学习指南与学习资源推荐
|
自然语言处理 编译器 Linux
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
833 0
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
|
6月前
|
SQL JavaScript 前端开发
❤Nodejs 第五章(操作本地数据库优化和处理)
【4月更文挑战第5天】本文介绍了在Node.js中操作本地数据库的优化和处理方法。首先展示了如何优化用户查询接口,根据用户条件查询用户列表。通过设置查询参数并使用axios发送GET请求,结合Express框架从`req.query`获取参数,实现动态SQL查询。接着,文章演示了根据用户ID查询用户详细信息,指出使用`req.params`而非`req.query`来获取URL路径中的动态ID。
70 5
|
6月前
编程笔记 01工具及参考资料
编程笔记 01工具及参考资料
|
6月前
|
SQL Oracle Java
java开发常见错误及其解决方式
java开发常见错误及其解决方式
|
Unix Linux API
[笔记]c++ 常见问题
[笔记]c++ 常见问题
168 0
|
自然语言处理 Go
Go语言编程快速入门
Go语言编程快速入门
113 0
|
网络架构 开发者 ice
3.3基础概念:调试配置介绍|学习笔记
快速学习3.3基础概念:调试配置介绍
3.3基础概念:调试配置介绍|学习笔记
|
存储 SQL Oracle
MySQL数据库快速入门到精通(超详细保姆级,建议收藏)这可能是目前最适合你的教程,从基础语法到实例演示。
此文章旨在为需要掌握快速开发和复习MySQL的同学所准备,您完全可以把此文章当作参考文档来使用,本文将尽量精简,使您快速的理解和掌握语法。
423 0
MySQL数据库快速入门到精通(超详细保姆级,建议收藏)这可能是目前最适合你的教程,从基础语法到实例演示。
|
开发者 Python
Python脚本编程常见问题学习笔记
快速学习Python脚本编程常见问题
Python脚本编程常见问题学习笔记
下一篇
无影云桌面