整型表达式比较的潜在危险

转自: http://blog.dreambrook.com/soloist/archive/2004/11/12/332.aspx

在程序里头经常会用到整数之间的大小比较,但是其中潜在的危险却往往被忽略了。例如一个内存拷贝函数:

void memcpy(void *pTo,void *pFrom,size_t size)
{
   assert(pTo != NULL && pFrom != NULL);

   while( --size >= 0)
   {
      *pTo++ = *pFrom++;
   }
}

    这个函数正确吗?如果你认为它永远都不可能跳出那个该死的循环就对了。size_t是一个无符号整数类型(VC6.0: typedef unsigned int
size_t,VC7.1: typedef unsigned __int64 size_t),所以--size得到的结果也是同样类型,而这样一个类型的值永远也不可能小于0!那我们尝试着改进它:

void memcpy(void *pTo,void *pFrom,size_t size)
{
   assert(pTo != NULL && pFrom != NULL);

   while( size-- > 0)
   {
      *pTo++ = *pFrom++;
   }
}
    这个版本中更改了循环条件,使得当size等于0的时候循环结束。危险消除了吗?嗯,消除了大部分,但是还存在着一个令人不愉快的地
方。如果有一个int类型的变量len,用它做size的实参来调用memcpy,又假设碰巧len的值小于0,那么会出现什么结果呢?size接收到了一个负值,但因为它本身是无符号型的,所以它会把这个负值解释成为无符号型整数,那必然是个正值,如此一来混乱可想而知。这就是一个典型的有符号/无符号不匹配错误。再看一段代码:

unsigned long a = 0;
long b = 0;
long c = 1;
if( (a - c) < b )
{
   // do something
}

if( (a - 1) < b )
{
   // do something
}

    这段代码的两个if语句的if分支有可能执行吗?答案是绝无可能。因为表达式(a - c)的类型不是long,而是unsigned long,它的值绝不会小于b(即0)。同样地,表达式(a - 1)的值也永远大于等于0。

    上面两个例子代表了我们在写程序时经常会犯的错误:无意识地滥用类型不匹配的变量、表达式(尤其是有符号型与无符号型)之间的赋值与比较。
    有什么办法能预防这种错误吗?事实上如果你足够警觉,将编译器的编译警告开关设为最高级(比如VC7.1的4级: /W4),那么任何一个负责
任的编译器都会在上述情况下明白无误地警告你。顺便说一下,VC工程中默认的编译警告为3级,此时编译器的责任心就大大降低了,对上述的危险情况根本视若无睹。
    所以为了让自己能够睡个安稳觉,首先应当尽量避免使用相异类型之间的赋值、比较。然后设定开发工具的检查为最严格等级,让它们能
帮我们尽早地嗅出这类潜在的危险。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值