是从C ++中较小的未定义行为中减去较大的无符号值吗? [英] Is subtracting larger unsigned value from smaller in C++ undefined behaviour?

查看:121
本文介绍了是从C ++中较小的未定义行为中减去较大的无符号值吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的程序中,在积分提升和通常的算术转换之后,运算符-的两个操作数都保持 unsigned long long 。之后,C ++ 11标准说:

In a program below after "integral promotions" and "usual arithmetic conversions" both operands of operator - remain unsigned long long. Afterwards, C++11 standard says:


5.7.3二进制-运算符的结果是减去从第一个开始的第二个操作数。

5.7.3 The result of the binary - operator is the difference resulting from the subtraction of the second operand from the first.

标准是否在任何地方更详细地定义了减法的精确执行方式(或引用了其他一些文档)

Does the standard define anywhere in more detail how exactly the subtraction is performed (or refers to some other document that defines it)?

是否从较小的无符号整数中减去较大的无符号整数会产生未定义的行为,为什么?

Does subtracting a larger unsigned integer from smaller unsigned integer produce an undefined behavior or not and why?

是否按照以下示例程序执行分配 c = ab 保证 c 将为 -3 在所有可能(甚至在理论上)符合C ++ 11标准的机器体系结构上,为什么?

Does performing an assignment c=a-b as in the example program below guarantee that c will be -3 on ALL (even theoretically) possible machine architectures compliant with C++11 standard and why?

int main()
{
    unsigned long long a=2, b=5;
    signed long long c=a-b;
}


推荐答案

无符号值的减法是由(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.

这篇关于是从C ++中较小的未定义行为中减去较大的无符号值吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆