0%

C++溢出的坑

C++的int只有32位,计算溢出也是十分普遍的事情,但我作死得尝试采用溢出的计算方法,结果发现千万不要代码中做溢出计算,编译器分分钟把你搞死。。

问题描述

1
2
int x = 0x7fffffff;
cout << !(x + x + 2) << endl;

根据常理,输出答案应该是1,2 * (0x7fffffff + 1) = 2 * 0x80000000 = 0,想想挺完美的吧,结果得出是0,百思不得其解,甚至尝试用了多个编译器,结果在我windows下的codeblocks中得到了1!

问题分析

查看了codeblocks的编译器,发现是32位的,其它编译器都是64位的,还以为是32位和64位的锅呢,然而并不是,实际是2014年编译器和2019年编译器的锅。。。

不死心的我把代码进行了汇编,终于发现了问题所在:

这是main函数的汇编截图,主要看赋值的那行开始的三行,首先第一句是赋值0x7fffffff-4(%rbp),然后把它和-1比较一下,就完事了???
Excuse me??
仔细思考一下的确也没错,!遇到0是1,也就是比较是否为0,也就是x + x + 2 == 0,优化一下就是x + 1 == 0。。

完全没想到是编译器太优秀了,帮我自行简化了,然而因为溢出的原因,x + x + 2 == 0其实有两个解。。

至于为什么我的codeblocks得到了1,是因为14年的编译器还比较傻,算的是2x == -2

结论

溢出的坑真的不能踩啊,还是得乖乖得写正确的代码,谁知道谁知道编译器哪天又太优秀了把代码优化了呢。