整型表达式比较的潜在危险
2004-11-09 20:36
337 查看
在程序里头经常会用到整数之间的大小比较,但是其中潜在的危险却往往被忽略了。例如一个内存拷贝函数:
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级,此时编译器的责任心就大大降低了,对上述的危险情况根本视若无睹。
所以为了让自己能够睡个安稳觉,首先应当尽量避免使用相异类型之间的赋值、比较。然后设定开发工具的检查为最严格等级,让它们能帮我们尽早地嗅出这类潜在的危险。
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级,此时编译器的责任心就大大降低了,对上述的危险情况根本视若无睹。
所以为了让自己能够睡个安稳觉,首先应当尽量避免使用相异类型之间的赋值、比较。然后设定开发工具的检查为最严格等级,让它们能帮我们尽早地嗅出这类潜在的危险。
相关文章推荐
- 用Indy控件,通过需要简单认证的SMTP服务器,发送带附件的Email。
- 海盗分黄金的故事,是老了点,但是还是很值得寻味的.
- 理解Subjects, Principals and Credentials
- eclipse技巧
- Native XML数据库技术详解
- 关于nucleus中的优先级查询表
- Shark1.0调试环境配置
- A 4000 SP通用分页类源码
- web滚动条设计思路
- sqlserver2000的jdbc驱动和PreparedStatement的性能问题。
- DotText二次开发手记之序
- 300个韩国网站欣赏
- Fundamentals of Object-Oriented Design in UML
- Universal Plug and Play
- 在JAVA中使用文档对象模型DOM经验小结[转载]
- rmvb也支持Target
- 编程实现启用禁用网卡
- Office 2003 里的 Document Image Writer 虚拟打印机
- XML中二进制数据的处理方法[转载]
- 一起 VS.NET 无法打开 ASP.NET 项目的经历及解决