2

n3337.pdf 草案 5.3.1.8 指出:

一元运算-符的操作数应具有算术或无范围枚举类型,结果是其操作数的否定。对整数或枚举操作数执行整数提升。无符号量的负数是通过从 2ⁿ 中减去其值来计算的,其中 n 是提升的操作数中的位数。结果的类型是提升的操作数的类型。

对于某些情况,这就足够了。假设 unsigned int 是 32 位宽,那么(-(0x80000000u)) == 0x80000000u,不是吗?

尽管如此,我还是找不到关于 unsigned 0x80000000 上的一元减号的任何信息。此外,C99 标准草案 n1336.pdf, 6.5.3.3 似乎对此一无所知:

一元 - 运算符的结果是其(提升的)操作数的负数。整数提升在操作数上执行,结果具有提升的类型。

UPDATE2:让我们假设 unsigned int 是 32 位宽。所以,问题是:C 中的一元减号(有符号和无符号)和 C++ 中的一元减号(仅有符号)呢?

UPDATE1:运行时行为和编译时行为(即常量折叠)都很有趣。

(相关:为什么是abs(0x80000000)== 0x80000000?

4

2 回答 2

5

对于您的问题,您所引用的报价的重要部分是:

无符号量的负数是通过从 2ⁿ 中减去其值来计算的,其中 n 是提升的操作数中的位数。

因此,要知道 的值-0x80000000u是什么,我们需要知道n的类型中的位数0x80000000u。这至少是 32,但这是我们所知道的(没有关于您的实现中类型大小的更多信息)。给定 的一些值n,我们可以计算出结果:

n   | -0x80000000u 
----+--------------
32  | 0x80000000
33  | 0x180000000
34  | 0x380000000
48  | 0xFFFF80000000
64  | 0xFFFFFFFF80000000

(例如,unsigned int16 位和unsigned long64 位的实现将具有 64 位n)。


C99 在 §6.2.5 Types p9 中隐藏了等效的措辞:

涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数字为模减少。

一元运算-符对除零以外的无符号操作数的结果将始终被此规则捕获。

对于 32 位int,类型0x80000000将为unsigned int,无论是否缺少u后缀,因此结果仍将是0x80000000type的值unsigned int

如果改为使用十进制常量2147483648,它将具有类型long并且计算将被签名。结果将是-2147483648type的值long

于 2012-02-28T00:52:57.973 回答
2

在 n1336, 6.3.1.3 Signed and Unsigned Integers 中,第 2 段定义了到无符号整数的转换:

否则,如果新类型是无符号的,则通过在新类型中可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内。

所以对于 32 位无符号整数,-0x80000000u==-0x80000000 + 0x100000000==0x80000000u.

于 2012-02-28T00:51:52.717 回答