IS(Int)(无符号)-1==未定义的行为

2022-03-22 00:00:00 overflow unsigned signed c++ c++11

我在试着理解这句话的意思:

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

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

  1. -1是签名int,并强制转换为无签名int。这样做的结果是,由于回绕行为,我们获得了可以由unsigned类型表示的最大值。

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

我的问题是:

  1. 我上面的解释正确吗?如果没有,则实际发生了什么。
  2. 这是我怀疑的未定义行为还是实现定义的行为。
PS:我知道如果它是未定义的行为(与定义的实现相反),那么我们就不能依赖程序的输出。因此,我们不能说我们将始终得到true还是false


解决方案

强制转换为unsigned int换行,此部分是合法的。

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

这两个强制转换相互抵消(同样,在C++20中得到保证,以前定义了实现,但在实践中仍然可以工作)。

带符号溢出通常是UB,是的,但这只适用于由计算引起的溢出。转换导致的溢出不同。

cppreference

如果目标类型是有符号的,则如果源整数可以用目标类型表示,则该值不会更改。否则结果为:

(直到C++20)实现定义

(从C++20开始)目标类型的唯一值等于源值的模2n,其中n是用于表示目标类型的位数。

(请注意,这与未定义的带符号整数算术溢出不同)。


有关转换如何工作的更多详细信息。

假设intunsigned int占用N位。

intunsigned int均可表示的值在转换过程中保持不变。所有其他值都将增加或减少2N以适合该范围。

这很方便,不会更改值的二进制表示形式。

例如int-1对应于unsigned int2N-1(最大的unsigned int值),两者都用二进制表示为11...11。同样,int-2N-1(最小int值)对应于unsigned int2N-1(最大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]

相关文章