我似乎无法在C标准中找到完全定义带有无符号操作数的一元减运算符的行为的相关部分.
2003 C++标准(是的,C++,我用几行代表)在5.3.1c7中说: The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of bits in the promoted operand.
然而,1999 C标准并未包含这样一个明确的陈述,也没有明确界定一元行为 - 在6.5.3.3c1,3和6.5c4中都没有.在后者中它说Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |, ...) ... return values that depend on the internal representations of integers, and have implementation-defined and undefined aspects for signed types.),它排除了一元减去,事情似乎仍然含糊不清.
这个早期的问题是指K&R ANSI C一书中的A.7.4.5节The negative of an unsigned quantity is computed by subtracting the promoted value from the largest value of the promoted type and adding one.
1999 C标准相当于本书的上述引用?
6.2.5c9说: A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
是吗?或者还有其他我想念的东西?
Rol*_*lig 17
是的,6.2.5c9正是您所寻找的段落.
一元减运算符对无符号操作数的行为与机器是否使用带符号数的二进制补码运算无关.相反,如果unsigned int x,y;该语句y=-x;将导致y接收为了使其x+y等于零而必须保持的任何值.如果x为零,y则同样为零.对于任何其他值x,它将是UINT_MAX-x+1,在这种情况下,算术值x+y将是UINT_MAX+1+(y-y),当分配给a时unsigned integer,将从中UINT_MAX+1减去,产生零.
在我所知道的每个实现中,负数都被计算为二进制补码......
int a = 12;
int b = -a;
int c = ~a + 1;
assert(b == c);
Run Code Online (Sandbox Code Playgroud)
...所以负有符号整数和“负”无符号整数之间实际上没有物理差异 - 唯一的区别在于它们的解释方式。
所以在这个例子中...
unsigned a = 12;
unsigned b = -a;
int c = -a;
Run Code Online (Sandbox Code Playgroud)
...b和c将包含完全相同的位。唯一的区别是b被解释为 2^32-12(或 2^64-12),而c被解释为“正常”-12。
因此,无论“符号性”如何,都以完全相同的方式计算负数,并且无符号和有符号之间的转换实际上是无操作(并且永远不会导致溢出,因为某些位需要“剪切”) -离开”)。