且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

是从C ++中较小的未定义行为中减去较大的无符号值吗?

更新时间:2023-11-10 19:12:22

无符号值的减法是由(3.9.1)[basic.fundamental] / 4定义:

The subtraction of unsigned values is well-defined by (3.9.1) [basic.fundamental]/4:


无符号整数,声明为 unsigned ,应遵循2 n 的算术定律,其中 n 是该特定大小的值表示中的位数 46

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.46

46)这意味着无符号算术运算不会溢出,因为结果不能用所得的无符号整数表示type以模的形式减少,该数量比所得的无符号整数类型可以表示的最大值大一。

46) This implies that unsigned arithmetic does not 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 unsigned integer type.

但是,赋值导致 c 具有实现定义的值(也就是说,您的里程可能会有所不同)。关于赋值运算符,(5.17)[expr.ass] / 3必须说

However, the assignment causes c to have an implementation-defined value (that is to say, your mileage may vary). About assignment operators, (5.17) [expr.ass]/3 has to say


如果左操作数不是类类型,则表达式将隐式转换(第4条)为左操作数的cv不合格类型。

If the left operand is not of class type, the expression is implicitly converted (Clause 4) to the cv-unqualified type of the left operand.

第4条([conv])在(4.7)中说。整数] / 3

And Clause 4 ([conv]) says in (4.7) [conv.integral]/3


如果目标类型是带符号的,则该值可以用目标类型(和位域宽度)表示; 否则,该值是实现定义的。

要重申: a-b 是定义明确的, c = a-b 不是因为 a-b 的结果是不能用 c 表示。

To reiterate: a - b is well-defined, c = a - b is not because the result of a - b is not representable by c.

这样做的历史原因是,尽管今天几乎所有计算机都对带符号整数使用二进制补码表示,但是在过去,有些机器使用了其他表示形式(尤其是一个人的补码和有符号幅值),与二进制补码的取值范围不同。如果以二进制补码表示形式的自然术语定义了无符号到有符号的转换,那么在这种机器上就不可能(或至少非常困难)实现C ++,并且如果对于其中一种表示形式使用自然术语来定义C ++,我们今天会有更大的问题。

The historical reason for this is that while today virtually all computers use two's complement representation for signed integers, back in the olden days there were machines that used other representations (notably one's complement and signed magnitude) that do not have the same value range as two's complement. Had unsigned-to-signed conversion been defined in terms natural for two's complement representation, C++ would have been impossible (or at least very difficult) to implement on such machines, and had it been defined in terms natural for one of those representations, we'd have a bigger problem today.