Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2377109
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: C/C++

2011-09-01 15:00:06

原文地址:容易弄错的函数返回值 作者:GFree_Wind

作者:  
博客: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都是由这些小问题引起的。

阅读(1360) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~