今天用 C 语言编程时,发现一个非常奇怪的现象:逻辑一切正常,输出却不对。采用 GDB 调试(可参考:gdb工具的使用),定位到错误,居然是乘法运算出了问题。两个数字相乘,结果却是不正确的,始终是错误的
。
问题发现
发现出问题的代码出现在:
usedSize = 0;
usedSize += pmInfo->videoSize*pmInfo->videoCnt;
usedSize += pmInfo->picSize*pmInfo->picCnt;
usedSize += pmInfo->logSize*pmInfo->logCnt;
usedSize += pmInfo->logIndexSize*pmInfo->logIndexCnt;
usedSize += pmInfo->videoIndexSize*pmInfo->videoIndexCnt;
usedSize += pmInfo->picIndexSize* pmInfo->picIndexCnt;
使用 GDB 定位到此的:
从上图可以看出, pmInfo->videoSize = 268435456,pmInfo->videoCnt= 146,二者相乘的结果应该是:
146 * 268435456 = 39191576576
但是,程序输出的结果却是 536870912
,这很奇怪。
现象分析
其实发生这种现象的原因真的非常白痴,就是 数据溢出
了。以我的机器为例,在 c 语言的计算过程中,所有乘数默认都是 int
型的,268435456 显然超出了 int
型能够表示的最大数据,计算当然出错了。
这种现象在编译时,其实就能避免,一般出现这种情况时,编译器会出现 warnning
警告的。以下是一个简单的测试 demo:
#include <stdio.h>
void main()
{
unsigned long long i = 0;
i = 146*0xffffff;
printf("i: %lld\n", i);
}
执行编译:
$ gcc -o test test.c
test.c: In function ‘main’:
test.c:7:12: warning: integer overflow in expression [-Woverflow]
i = 146*0xffffff;
^
$ ./test
i: -1845493906
很明显,编译器已经提示我们 overflow 了。
开发时,我习惯先忽略 warnning
,最后再一起解决。这不是一个好习惯,我们也不该忽略它。
解决问题
知道原因,解决起来其实很简单,加上强制转换符就可以了,如下:
#include <stdio.h>
void main()
{
unsigned long long i = 0;
i = 146*(unsigned long long)0xffffff;
printf("i: %lld\n", i);
}
再编译执行,发现问题已经解决了。
$ gcc -o test test.c
$ ./test
i: 2449473390