我似乎无法在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.)
,它排除了一元减号,事情似乎仍然模糊不清。
This earlier question是指K&amp; 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.
答案 0 :(得分:15)
是的,6.2.5c9正好是您要查找的段落。
答案 1 :(得分:6)
一元减运算符对无符号操作数的行为与机器是否使用带有符号数的二进制补码运算无关。相反,给定unsigned int x,y;
语句y=-x;
将使y
接收为使x+y
等于零而必须保持的任何值。如果x
为零,则y
同样为零。对于x
的任何其他值,它将为UINT_MAX-x+1
,在这种情况下,x+y
的算术值将为UINT_MAX+1+(y-y)
,当分配给unsigned integer
时,将从中减去UINT_MAX+1
,产生零。
答案 2 :(得分:3)
在我所知道的每个实施中,负数计算为two's complement ......
int a = 12;
int b = -a;
int c = ~a + 1;
assert(b == c);
...所以在负面签名和“负面”无符号整数之间确实没有物理差异 - 唯一的区别在于它们是如何解释。
所以在这个例子中......
unsigned a = 12;
unsigned b = -a;
int c = -a;
... b
和c
将包含完全相同的位。唯一的区别是b
被解释为2 ^ 32-12(或2 ^ 64-12),而c
被解释为“正常”-12。
因此,无论“sign-ness”如何,负数都以完全相同的方式计算,无符号和有符号之间的转换实际上是无操作(并且在某些位需要的情况下永远不会导致溢出被“切断”)。
答案 3 :(得分:1)
这很晚了,但是无论如何...
C指出(很困难,正如其他答案中已经提到的那样)
任何无符号类型都是具有特定类型的二进制表示形式 位数
对无符号类型的所有算术运算都已完成(mod 2 ^ N),'mod' 是模数的数学定义,“ N”是 用于表示类型的位数。
应用于无符号类型的一元减号运算符的行为就像该值将被提升为下一个更大的有符号类型,然后取反,然后再次转换为无符号并被截断为源类型。 (这是一个略微的简化,因为整数提升适用于所有位数少于'int'的类型,但是我认为它足够接近了。)
某些编译器确实在将一元减号应用于无符号类型时确实发出警告,但这仅是为了程序员的利益。恕我直言,该结构定义明确且可移植。
但是,如果有疑问,请不要使用一元减号:写“ 0u-x”而不是“ -x”,一切都会好起来的。除非完全禁用优化,否则任何体面的代码生成器都将由此创建一个否定指令。