分类: C/C++
2011-06-14 12:03:18
作者:
博客:linuxfocus.blog.chinaunix.net
在我们写代码的过程中,有很多函数由于经常的被调用,加上我们主观的惯性思维,认为这些函数很简单,结果反而更容易出错。
下面是我认为两个容易出错的函数,特点都是频繁被使用,但是对其返回值,我相信并不是所有人都很清楚。
1. snprintf:
缓冲区溢出是大多数软件容易出的bug,也是容易被攻击的地方。所以,现在的软件中,都开始使用snprintf代替sprintf,用strncpy代替strcpy。
但是现在谁能说出snprintf的返回值都有什么?
int snprintf(char *str, size_t size, const char *format, ...);——这是snprintf的原型。
它的返回值有如下几种情况:
1,负值:这个自然是出错了,很简单略过不提。
2,str的size足够大,那么返回实际打印字节数(不包括结尾的'\0');
3,str的size不足,返回的是什么呢?返回的不是实际打印字节数,而是要打印的字节数,其等于size或者大于size。
关于这最后一种情况,我相信至少有一半的程序员不知道或者不清楚,那么就很容易出现bug了。
2. fwrite/fread:
文件的I/O函数,在我们第一门的编程语言中都会涉及,但是如果一不小心,还是会出错。
其原型是size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
那么它的返回值什么?
还是估计一下,我猜测大概有1/10的人,返回的是写入的字节数。而正确答案是返回的是成功写入元素的个数——这个个数对应于参数中的count。
上面两个函数都是我们平时经常接触到的,认为很简单的函数,但是一不小心还是会出错。其实不只是返回值,还有一些函数也会导致我们错误的使用。我再举两个简单的函数。
1. strncpy.
char buf[MAX_SIZE];
strncpy(buf, str, ?)
这第三个参数应该填什么?根据snprintf的使用习惯,我们很容易选择使用sizeof(buf),那么这个表达式就是strncpy(buf, str, sizeof(buf))。
如果这么使用的话,恭喜你,引入了一个bug。
当我们使用snprintf的时候,如果buffer不够大的话,API虽然会截断字符串,但是buffer的结尾仍然会填上'\0'。但是strncpy不会。
这样当buffer不够大时,虽然这句strncpy不会有问题,但是,当你使用buf中的字符串时,就会出现问题,因为每月字符串结束符'\0'。
2. malloc和realloc
请看下面的两行代码,是否会引起crash。
char *p1 = malloc(0);
*p1 = 'a';
答案是不会。当malloc的参数是0时,实际上是系统仍然会分配一个字节的空间给p1。所以并不会引起crash。
那么,我们再接着加上2行代码,大家看看有没有问题。
p2 = realloc(p1, 0);
*p2 = 'a';
答案是系统会crash。因为realloc是一个很讨人厌的函数——一个函数被赋予了2项功能。
realloc的原型如下:
void * realloc ( void * ptr, size_t size );当size大于0的时候,realloc是先施放ptr的内存,然后再申请size大小的内存返回;
但是当size等于0的时候,realloc却等于free。它将ptr指向的内存释放,并返回null。
这样上面的代码就会引起程序的crash。
因此可见,在我们编程的过程中,有多少小问题容易被忽视,而大多数bug都是由这些小问题引起的。