C++中的符号扩展是编译器选项,还是编译器相关或依赖于目标?

-3 c++ compiler-options

以下代码已在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);}
Run Code Online (Sandbox Code Playgroud)

结果产生2个结果: -5 或者4294967291

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

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

Dan*_*our 5

您的问题是您假设unsigned long int是32位宽并且signed long long是64位宽.这个假设是错误的.

我们可以通过使用具有保证(通过标准)位宽的类型来可视化正在发生的事情:

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;
}
Run Code Online (Sandbox Code Playgroud)

在这三种情况中的每一种情况下,表达式都会small - large产生无符号整数类型(相应宽度)的结果.该结果使用模运算来计算.

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

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


要突出LưuVĩnhPhúc的评论:

Operand1-Operand2因此,在转换为s64时,它是无符号的,它总是为零扩展.[..]

符号扩展仅在第一种情况下完成,因为只有那时存在扩展转换,并且它实际上始终为零扩展.


标准引用,强调我的.关于small - large:

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模数2^n$,其中n是用于表示无符号类型的位数).[..]

§4.7/ 2

关于从无签名到签名的转换:

如果[整数转换]的目标类型是有符号的,则如果它可以在目标类型中表示,则该值不变; 否则,该值是实现定义的.

§4.7/ 3