是 (int)(unsigned)-1 == -1 未定义的行为

Is (int)(unsigned)-1 == -1 undefined behavior

我正在尝试理解语句的含义:

(int)(unsigned)-1 == -1;

根据我目前的理解,会发生以下情况:

  1. -1signed int 并转换为 unsigned int。这样做的结果是,由于环绕行为,我们得到了 unsigned 类型可以表示的最大值。

  2. 接下来,我们在步骤 1 中获得的这个 unsigned 类型最大值现在被转换为 signed int。但是注意这个最大值是一个unsigned type。所以这 超出 signed type 的范围 。由于有符号整数溢出是未定义的行为,程序将导致 未定义的行为

我的问题是:

  1. 我上面的解释对吗?如果不是,那么实际发生了什么。
  2. 这是我怀疑的未定义行为还是实现定义的行为。

PS:我知道如果它是未定义的行为(与定义的实现相反),那么我们不能依赖程序的输出。所以我们不能说我们是否总是会得到 truefalse.

编辑:C++ 20 之前的版本不需要补码

这可能有助于理解 -1 的二进制表示形式,即: 0b1111'1111'1111'1111'1111'1111'1111'1111。我应该注意,这是 -1 的 4 字节表示。不同的机器可能代表 int 不同。

您正在转换为 unsigned,然后又转换回 int,这会改变您对 1 和 0 的解释方式。在十进制(或有时称为 denary)中,您所做的相当于将其转换为 4294967295 然后返回 -1.

The type of the integer literal is the first type in which the value can fit, from the list of types which depends on which numeric base and which integer-suffix was used

因为 -1 适合 int,这就是它的解释方式。 参见:https://en.cppreference.com/w/cpp/language/integer_literal

this is out of range of the signed type. And since signed integer overflow

这是不是整数溢出。这是二进制表示。整数溢出将是:

    int int_max = 2147483647; // this is the maximum integer int on my machine
    int one = 1;             
    
    int overflow = x + s;         // sum is equal to -2147483648

以上是整数溢出的例子,因为最大表示

转换为unsigned int回绕,这部分是合法的。

超出范围转换为 int 从 C++20 开始是合法的,并且之前是实现定义的(但无论如何在实践中都能正常工作)。这里没有UB

这两个转换相互抵消(同样,在 C++20 中得到保证,以前定义的实现,但无论如何在实践中都有效)。

有符号溢出通常是 UB,是的,但这仅适用于由计算引起的溢出。一次转换造成的溢出是不同的。

cppreference

If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is:

(until C++20) implementation-defined

(since C++20) the unique value of the destination type equal to the source value modulo 2<sup>n</sup> where n is the number of bits used to represent the destination type.

(Note that this is different from signed integer arithmetic overflow, which is undefined).


关于转换工作原理的更多细节。

假设intunsigned int占用N位。

intunsigned int 都可以表示的值在转换后没有改变。所有其他值增加或减少 2N 以适应范围。

这不会更改值的二进制表示形式。

例如int-1对应unsigned int2<sup>N</sup>-1(最大unsigned int值) , 两者都用二进制表示为 11...11 。同理,int-2<sup>N-1</sup>(最小int值)对应unsigned int2<sup>N-1</sup>(最大int值+1).

int:   [-2^(n-1)] ... [-1] [0] [1] ... [2^(n-1)-1]
            |           |   |   |           |
            |           '---|---|-----------|-----------------------.
            |               |   |           |                       |
            '---------------|---|-----------|----------.            |
                            |   |           |          |            |
                            V   V           V          V            V
unsigned int:              [0] [1] ... [2^(n-1)-1] [2^(n-1)] ... [2^n-1]