Ale*_*x24 21 c++ unsigned-integer
在被建议阅读"Stanley B. Lipman编着的C++ Primer 5"后,我不明白这一点:
第66页."涉及无符号类型的表达式"
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
Run Code Online (Sandbox Code Playgroud)
他说:
在第二个表达式中,int值-42在添加完成之前转换为unsigned.将负数转换为无符号的行为就像我们尝试将该负值分配给无符号对象一样.如上所述,值"环绕".
但如果我做这样的事情:
unsigned u = 42;
int i = -10;
std::cout << u + i << std::endl; // Why the result is 32?
Run Code Online (Sandbox Code Playgroud)
如您所见-10,未转换为unsigned int.这是否意味着一个比较提倡之前发生signed integer到unsigned integer?
Nat*_*ica 26
-10正被转换为一个非常大的值的无符号整数,你得到一个小数字的原因是加法包裹你回来.32位无符号整数-10与4294967286.当你添加42 4294967328,但最大值是4294967296,所以我们必须采用4294967328模数4294967296,我们得到32.
bol*_*lov 17
好吧,我想这是"两个错误不能做对"的例外:)
发生的事情是,实际上有两个环绕(无符号溢出),最终结果在数学上是正确的.
首先,i转换为无符号,并根据环绕行为的值std::numeric_limits<unsigned>::max() - 9.
当这个值与u数学结果相加时,std::numeric_limits<unsigned>::max() - 9 + 42 == std::numeric_limits<unsigned>::max() + 33哪个是溢出,我们得到另一个环绕.所以最终的结果是32.
作为算术表达式的一般规则,如果只有无符号溢出(无论多少),并且最终的数学结果在表达式数据类型中是否可表示,那么表达式的值将是数学上正确的值.这是因为C++中的无符号整数遵循算术模2n的定律(见下文).
重要的提醒.根据C++无符号算术不会溢出:
§6.9.1基本类型[basic.fundamental]
- 无符号整数应遵守算术模2 n的定律,其中n是整数特定大小的值表示中的位数49
49)这意味着无符号算术不会溢出,因为无法通过结果无符号整数类型表示的结果以比模式生成的无符号整数类型所表示的最大值大1的数量为模.
但是,我会在答案中留下"溢出"来表达无法在常规算术中表示的值.
我们通俗地称之为"环绕"的实际上只是无符号整数的算术模数性质.然而,我会使用"环绕",因为它更容易理解.
i事实上是晋升为unsigned int.
C和C++中的无符号整数在ℤ/ 2 n implement中实现算术,其中n是无符号整数类型中的位数.我们得到了
[42] + [-10]≡[42] + [2 n - 10]≡[2 n + 32]≡[32],
用[x]表示in/2 n x中x的等价类.
当然,在正式发生时,只挑选每个等价类的非负代表的中间步骤不一定是解释结果的必要步骤; 直接的
[42] + [-10]≡[32]
也是对的.
| 归档时间: |
|
| 查看次数: |
1864 次 |
| 最近记录: |