一元减去0x80000000(有符号和无符号)

时间:2012-02-28 00:41:33

标签: c++ c standards unary-operator

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:运行时行为和编译时行为(即常量折叠)都很有趣。

(相关:Why is abs(0x80000000) == 0x80000000?

2 个答案:

答案 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位int0x80000000的类型将为unsigned int,无论缺少u后缀,因此结果仍然是值类型为0x80000000的{​​{1}}。

如果您使用小数常量unsigned int,它将具有类型2147483648并且计算将被签名。结果将是值为long的值-2147483648

答案 1 :(得分:2)

在n1336,6.3.1.3有符号和无符号整数中,第2段定义了转换为无符号整数:

  

否则,如果新类型是无符号的,则转换为   重复加或减一个以上的最大值   可以用新类型表示,直到值在范围内   新类型。

因此对于32位无符号整数-0x80000000u==-0x80000000 + 0x100000000==0x80000000u