一个负整数与一个更大的无符号整数相加,是否提升为unsigned int?

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 integerunsigned integer

Nat*_*ica 26

-10正被转换为一个非常大的值的无符号整数,你得到一个小数字的原因是加法包裹你回来.32位无符号整数-104294967286.当你添加42 4294967328,但最大值是4294967296,所以我们必须采用4294967328模数4294967296,我们得到32.

  • @ Alex24欢迎你.`short`和`char`被提升为`int`,因为这是数学运算符使用的最小内置类型.只有当你有一个`unsigned char`或`unsigned short`并且它与`int`具有相同的大小时,唯一可能不同的时间.然后它将被提升为`unsigned int`. (2认同)

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]

  1. 无符号整数应遵守算术模2 n的定律,其中n是整数特定大小的值表示中的位数49

49)这意味着无符号算术不会溢出,因为无法通过结果无符号整数类型表示的结果以比模式生成的无符号整数类型所表示的最大值大1的数量为模.

但是,我会在答案中留下"溢出"来表达无法在常规算术中表示的值.

我们通俗地称之为"环绕"的实际上只是无符号整数的算术模数性质.然而,我会使用"环绕",因为它更容易理解.

  • @BaummitAugen是什么?当然它溢出来了.添加两个大的无符号整数,不能表示不符合数字格式的数字 (3认同)
  • @BaummitAugen 我去了标准来证明我的观点。原来我错了。谢谢你。 (2认同)
  • @GarrGodfrey我搜索了标准,他的确是正确的.没有溢出.这是因为无符号整数不代表自然数,但正如BaummitAugen所说,它们代表等价类. (2认同)
  • @curiousguy我听说过一些ppl(专家)说,事后看来,对unsigned进行环绕行为是一个糟糕的决定.然而,它们的主要原因是它所抑制的优化.他们认为常规unsigned在溢出时具有未定义的行为,并且存在一些具有环绕行为的其他数据类型.但是它就是这样啊. (2认同)
  • @curiousguy*"那么为什么有人会用它们来表示一些字节,一个容器中的一些对象等等."一个委员会的几位着名成员正好考虑到这是一个历史错误.https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything 9:50,42:40,1:02:50 (2认同)

Bau*_*gen 5

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]

也是对的.