我正在尝试理解语句的含义:
(int)(unsigned)-1 == -1;
据我目前的理解,会发生以下事情:
-1
是一个 signedint
并被强制转换为 unsignedint
。这样做的结果是,由于环绕行为,我们得到了unsigned
类型可以表示的最大值。接下来,我们在步骤 1 中得到的这个
unsigned
类型最大值现在被转换为signed int
。但请注意,这个最大值是一个无符号类型
。所以这是签名类型
的超出范围。而且由于有符号整数溢出是未定义的行为,程序会导致未定义的行为。
我的问题是:
- 我上面的解释正确吗?如果不是,那么实际发生了什么。
- 这是我怀疑的未定义行为还是实现定义的行为。
PS:我知道如果它是未定义的行为(与定义的实现相反),那么我们不能依赖程序的输出。所以我们不能说我们是否总是会得到 true
或 false
。
最佳答案
转换为 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]
关于c++ - 是 (int)(unsigned)-1 == -1 未定义的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70797019/