是 (int)(unsigned)-1 == -1 未定义的行为
Is (int)(unsigned)-1 == -1 undefined behavior
我正在尝试理解语句的含义:
(int)(unsigned)-1 == -1;
根据我目前的理解,会发生以下情况:
-1
是 signed int
并转换为 unsigned int
。这样做的结果是,由于环绕行为,我们得到了 unsigned
类型可以表示的最大值。
接下来,我们在步骤 1 中获得的这个 unsigned
类型最大值现在被转换为 signed int
。但是注意这个最大值是一个unsigned type
。所以这 超出 signed type
的范围 。由于有符号整数溢出是未定义的行为,程序将导致 未定义的行为。
我的问题是:
- 我上面的解释对吗?如果不是,那么实际发生了什么。
- 这是我怀疑的未定义行为还是实现定义的行为。
PS:我知道如果它是未定义的行为(与定义的实现相反),那么我们不能依赖程序的输出。所以我们不能说我们是否总是会得到 true
或 false
.
编辑: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,是的,但这仅适用于由计算引起的溢出。一次转换造成的溢出是不同的。
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).
关于转换工作原理的更多细节。
假设int
和unsigned int
占用N位。
int
和 unsigned int
都可以表示的值在转换后没有改变。所有其他值增加或减少 2N 以适应范围。
这不会更改值的二进制表示形式。
例如int
-1
对应unsigned int
2<sup>N</sup>-1
(最大unsigned int
值) , 两者都用二进制表示为 11...11
。同理,int
-2<sup>N-1</sup>
(最小int
值)对应unsigned int
2<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]
我正在尝试理解语句的含义:
(int)(unsigned)-1 == -1;
根据我目前的理解,会发生以下情况:
-1
是 signedint
并转换为 unsignedint
。这样做的结果是,由于环绕行为,我们得到了unsigned
类型可以表示的最大值。接下来,我们在步骤 1 中获得的这个
unsigned
类型最大值现在被转换为signed int
。但是注意这个最大值是一个unsigned type
。所以这 超出signed type
的范围 。由于有符号整数溢出是未定义的行为,程序将导致 未定义的行为。
我的问题是:
- 我上面的解释对吗?如果不是,那么实际发生了什么。
- 这是我怀疑的未定义行为还是实现定义的行为。
PS:我知道如果它是未定义的行为(与定义的实现相反),那么我们不能依赖程序的输出。所以我们不能说我们是否总是会得到 true
或 false
.
编辑: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,是的,但这仅适用于由计算引起的溢出。一次转换造成的溢出是不同的。
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>
wheren
is the number of bits used to represent the destination type.(Note that this is different from signed integer arithmetic overflow, which is undefined).
关于转换工作原理的更多细节。
假设int
和unsigned int
占用N位。
int
和 unsigned int
都可以表示的值在转换后没有改变。所有其他值增加或减少 2N 以适应范围。
这不会更改值的二进制表示形式。
例如int
-1
对应unsigned int
2<sup>N</sup>-1
(最大unsigned int
值) , 两者都用二进制表示为 11...11
。同理,int
-2<sup>N-1</sup>
(最小int
值)对应unsigned int
2<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]