当我们进行各种数学计算(四则运算,指数运算等)时,要时刻保持警惕,防止运算结果的溢出(上溢或下溢);当进行不同类型的数据混合运算时,要注意数据类型的提升或转换,避免精度丢失。
注:本文如无特别说明,示范代码均在 Win7 64位英文系统, Dev-C++ 4.9 环境下编译执行。
#include<stdio.h> int main() { //unsigned int i = 10; size_t i = 10; while(i >= 0) { printf("%u\t", i); i--; /* 当 i 为 0 时, i-- 操作导致下溢翻转,变成该整型所能表示的最大值而导致死循环 */ } return 0; }
对于无符号整数类型(unsigned char, unsigned short , unsigned int, unsigned long 以及宏定义 size_t 等),执行自减操作就会下溢而翻转,变成该整型的最大值,从而导致死循环的发生。
避免这种错误最简单的方式就是不要用无符号整数执行自减运算时与 0 进行相等比较;或者避免使用无符号整型进行此类操作。对于示范代码,将 ”size_t“ 改成 ”int", 或者修改 “ while(i >= 0)" 为 " while(i > 0)"的判断(当然判断条件的意思也变了)。
#include<stdio.h> int main() { <span style="white-space:pre"> </span>int a = 2147483647; <span style="white-space:pre"> </span>int b = -2147483648; <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>printf("a = %d, a + 1 = %d\n", a, a + 1); <span style="white-space:pre"> </span>printf("b = %d, b - 1 = %d", b, b - 1); <span style="white-space:pre"> </span>return 0; }
a = 2147483647, a + 1 = -2147483648 b = -2147483648, b - 1 = 2147483647完全不是我们正常的数学运算哦!正数相加反而变小了,负数相加反而变大了呢!这正是由于数据类型在计算机中是以二进制形式表达的,且位数有限,超出表达范围就会发生翻转。
#include<stdio.h> int main() { double d; int i; d = 9.5 + 1/2; i = 9.5 + 1/2; printf("d = %lf, i = %d\r\n", d, i); return 0; }
d = 9.500000, i = 9而我们期望结果,应该是 d = 10, i = 10。这其中就涉及到数据类型转换和提升的概念,该问题比较复杂,后续些专文讲解。简而言之,对于 d = 9.5 + 1/2 而言, 1/2 由于都是整数相除,其结果也为整数,故将结果 0.5 向 0 方向取整为0, 如果改成 d = 9.5 + 1.0/2, 则 d = 10 了。对于 i = 9.5 + 1 /2, 同样的道理。