C++ 中的 Sign Extension 是编译器选项,还是依赖于编译器或依赖于目标?

Is Sign Extension in C++ a compiler option, or compiler dependent or target dependent?

以下代码已在 3 个不同的编译器和 3 个不同的处理器上编译并给出了 2 个不同的结果:

typedef unsigned long int u32;
typedef signed long long s64;
int main ()
{ u32 Operand1,Operand2;
  s64 Result;
  Operand1=95;
  Operand2=100;
  Result= (s64)(Operand1-Operand2);}

结果产生 2 个结果: 任何一个 -54294967291

我明白 (Operand1-Operand2) 的操作是在 32 位无符号计算中完成的,然后当转换为 s64 符号扩展在第一种情况下正确完成但没有正确完成第二种情况。

我的问题是符号扩展是否可以通过编译器选项来控制,或者它依赖于编译器或者它可能依赖于目标。

符号扩展依赖于平台,其中平台是编译器、目标硬件体系结构和操作系统的组合。

此外,正如 Paul R 提到的,内置类型的宽度(如 unsigned long)也取决于平台。使用 <cstdint> 中的类型来获取固定宽度的类型。尽管如此,它们只是依赖于平台的定义,因此它们的符号扩展行为仍然取决于平台。

Here is a good almost-duplicate question about type sizes. And here 很好 table 关于字体大小的关系。

您的问题是您假设 unsigned long int 是 32 位宽而 signed long long 是 64 位宽。 这个假设是错误的

We can visualize what's going on by using types that have a guaranteed (by the standard) bit width:

int main() {
    {
        uint32_t large = 100, small = 95;
        int64_t result = (small - large);
        std::cout << "32 and 64 bits: " << result << std::endl;
    }  // 4294967291
    {
        uint32_t large = 100, small = 95;
        int32_t result = (small - large);
        std::cout << "32 and 32 bits: " << result << std::endl;
    }  // -5
    {
        uint64_t large = 100, small = 95;
        int64_t result = (small - large);
        std::cout << "64 and 64 bits: " << result << std::endl;
    }  // -5
    return 0;
}

在这三种情况中的每一种情况下,表达式 small - large 都会产生 unsigned 整数类型(根据宽度)的结果。这个结果是用模运算计算出来的。

在第一种情况下,因为无符号结果可以存储在更宽的有符号整数中,所以不执行值的转换。

在其他情况下,结果不能存储在有符号整数中。因此执行了实现定义的转换,这通常意味着将无符号值的位模式解释为有符号值。因为结果是 "large",最高位将被设置,当被视为有符号值时(在二进制补码下)相当于 "small" 负值。


突出 Lưu Vĩnh Phúc 的评论:

Operand1-Operand2 is unsigned therefore when casting to s64 it's always zero extension. [..]

符号扩展只在第一种情况下进行,因为只有在这种情况下才有扩大转换,而且确实总是零扩展。


引自 the standard,强调我的。关于small - large

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n$ where n is the number of bits used to represent the unsigned type). [..]

§ 4.7/2

关于从无符号到有符号的转换:

If the destination type [of the integral conversion] is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.

§ 4.7/3

类型提升,相应的符号扩展由C++语言指定。

没有指定但与平台相关的是所提供的整数类型的范围。它甚至符合标准,charshort intintlong intlong long int 都具有相同的范围,前提是该范围满足 C++ 标准要求对于 long long int。在这样的平台上,不会发生扩大或缩小,但有符号<->无符号转换仍然可以改变值。