#include <iostream>
int main()
{
unsigned u = 10;
int i = -42;
std::cout << i+i << std::endl;
std::cout << u+i << std::endl;
return 0;
}
不知道大家口算的结果是什么样的,下面是我的编译器的输出结果:
对于这个结果,如果大家没感到惊讶,好吧我承认你是大神,对于弱者我来说百思不得姐啊第二个结果,怎么就得到那么大的数了呢?
一番恶搞之下终于算是弄明白了:
如果表达式里既有带符号类型又有无符号类型,当带符号类型为负时可能出现异常结果,因为C++带符号数会自动转换成无符号数,拿
上面的第二个表达式来说,进行运算时,首先-42会被转换为无符号数。把负数转换成无符号数类似于直接给无符号数赋一个负值,结果
等于这个负数加上无符号数的模。
其实这个结果是根据实现的不同而不同的,就是说,我的机子 int 是32位,所以输出是4294967264。下面是内部原理:
首先,无符号数用二进制表示时无符号位!
42在计算机中的存储(32位int):00000000000000000000000000101010
那么-42就是对它求补而得: 11111111111111111111111111010110
好,再加上10,就是 + 00000000000000000000000000001010
-------------------------------------------------------------------
11111111111111111111111111100000
得到的是多少呢? Result = 2^32 - 11111(B) - 1 = 2^32 - 1 - 31 = 4294967264
自此,问题得到解答!
所以最后想说,在含有无符号类型的表达式里,一定要小心!
无符号数不会小于0这一事实也影响着循环的写法。例如,我们要通过控制变量低贱的方式把从10到0的数字降序输出。这个循环可以这样写:
for(int i = 10; i >= 0; --i)
std::cout << i << std::endl;
可能你觉得反正也不打算输出负数,可以用无符号数来重写这个循环:
for(unsigned i = 10; i >= 0; --i)
std::cout << i << std::endl;
我们来看当i = 0时发生了什么,这次迭代输出0, 然后继续执行for语句里的表达式,--i从i当中减去1,得到的-1并不满足无符号数的要求,此时
像所有表示范围之外的其他数字一样,-1被自动转换为一个合法的无符号数。假设int 类型占32位,则当i=0时,--i的结果是4294967295!!!
一种解决方法是用while循环:
unsigned u = 11;
while(u > 0)
{
--u;
std::cout << u << endl;
}