我要努力工作,加油!

c语言编程,两数相乘,结果总是不对,不符合预期

		发表于: 2018-06-19 11:18:34 | 已被阅读: 48 | 分类于: Linux笔记
		
今天用 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