n3337.pdf草案5.3.1.8规定:
一元
-
运算符的操作数应具有算术或无范围的枚举类型,结果是其操作数的否定。对整数或枚举操作数执行整体提升。通过从2ⁿ减去其值来计算无符号数量的负数,其中n是提升的操作数中的位数。结果的类型是提升的操作数的类型。
在某些情况下,这就足够了。假设unsigned int是32位宽,那么(-(0x80000000u)) == 0x80000000u
,不是吗?
但是,我无法找到关于无符号0x80000000上的一元减号的任何内容。此外,C99标准草案n1336.pdf,6.5.3.3似乎没有提及它:
一元运算符的结果是其(提升的)操作数的否定。整数提升在操作数上执行,结果具有提升类型。
UPDATE2:我们假设unsigned int是32位宽。所以,问题是:C中的一元减号(有符号和无符号)和C ++中的一元减号(仅签名)?
UPDATE1:运行时行为和编译时行为(即常量折叠)都很有趣。
答案 0 :(得分:5)
对于您的问题,您所包含的报价的重要部分是:
无符号数量的负数是通过减去它来计算的 来自2ⁿ的值,其中n是提升操作数中的位数。
因此,要知道-0x80000000u
的价值是什么,我们需要知道n
类型中0x80000000u
的位数。这至少是32,但这是我们所知道的(没有关于实现中类型大小的更多信息)。给定n
的某些值,我们可以计算出结果:
n | -0x80000000u
----+--------------
32 | 0x80000000
33 | 0x180000000
34 | 0x380000000
48 | 0xFFFF80000000
64 | 0xFFFFFFFF80000000
(例如,unsigned int
为16位且unsigned long
为64位的实现将具有64的n
。
C99在§6.2.5类型p9中隐藏了相同的措辞:
涉及无符号操作数的计算永远不会溢出,因为 结果无法由结果无符号整数表示 type是以大于最大值的数量减少的模数 可以由结果类型表示的值。
除了零之外的无符号操作数上的一元-
运算符的结果将始终被此规则捕获。
使用32位int
,0x80000000
的类型将为unsigned int
,无论缺少u
后缀,因此结果仍然是值类型为0x80000000
的{{1}}。
如果您使用小数常量unsigned int
,它将具有类型2147483648
并且计算将被签名。结果将是值为long
的值-2147483648
。
答案 1 :(得分:2)
在n1336,6.3.1.3有符号和无符号整数中,第2段定义了转换为无符号整数:
否则,如果新类型是无符号的,则转换为 重复加或减一个以上的最大值 可以用新类型表示,直到值在范围内 新类型。
因此对于32位无符号整数-0x80000000u==-0x80000000 + 0x100000000==0x80000000u
。