37

我似乎无法在 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.

是这样吗?还是我还缺少其他东西?

4

4 回答 4

19

是的,6.2.5c9 正是您要查找的段落。

于 2011-11-06T11:45:20.717 回答
10

一元减运算符对无符号操作数的行为与机器是否使用带符号数的补码运算无关。相反,鉴于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减去它,产生零。

于 2015-06-22T20:40:50.753 回答
4

在我知道的每个实现中,负数都被计算为二进制补码......

int a = 12;
int b = -a;
int c = ~a + 1;
assert(b == c);

...所以负有符号整数和“负”无符号整数之间实际上没有物理区别 - 唯一的区别在于它们的解释方式

所以在这个例子中......

unsigned a = 12;
unsigned b = -a;
int c = -a;

... bandc将包含完全相同的位。唯一的区别是b被解释为 2^32-12(或 2^64-12),而c被解释为“正常”-12。

因此,无论“符号性”如何,都以完全相同的方式计算负数,并且无符号和有符号之间的转换实际上是无操作的(并且在某些位需要“剪切”的意义上永远不会导致溢出-离开”)。

于 2011-11-06T12:50:57.587 回答
2

这已经晚了,但无论如何...

C 声明(以一种相当困难的方式,正如其他答案中已经提到的那样)

  • 任何无符号类型都是具有特定类型位数的二进制表示

  • 无符号类型的所有算术运算都已完成(mod 2^N),“mod”是模数的数学定义,“N”是用于表示类型的位数。

应用于无符号类型的一元减运算符的行为就像该值将被提升为下一个更大的有符号类型,然后取反,然后再次转换为无符号并截断为源类型。(这是一个轻微的简化,因为整数提升发生在所有位数少于“int”的类型上,但我认为它已经足够接近了。)

一些编译器在将一元减号应用于无符号类型时确实会发出警告,但这仅仅是为了程序员的利益。恕我直言,该构造定义明确且可移植。

但如果有疑问,不要使用一元减号:写 '0u - x' 而不是 '-x',一切都会好起来的。除非完全禁用优化,否则任何体面的代码生成器都会从中创建一个否定指令。

于 2020-11-05T07:50:18.083 回答