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

时间:2016-11-03 08:10:09

标签: 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);}

结果产生2个结果: 或 -54294967291

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

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

3 个答案:

答案 0 :(得分:5)

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

We can visualize what's going on使用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都会产生无符号整数类型(相应宽度)的结果。该结果使用模运算计算。

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

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

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

  

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

符号扩展仅在第一种情况下完成,因为只有扩展转换,并且它确实总是零扩展。

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

  

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

     

§4.7/ 2

关于从unsigned转换为signed:

  

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

     

§4.7/ 3

答案 1 :(得分:2)

符号扩展与平台相关,其中platform是编译器,目标硬件架构和操作系统的组合。

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

Here是关于类型大小的几乎重复的问题。 here是关于类型大小关系的好表。

答案 2 :(得分:1)

键入促销,相应的符号扩展名由C ++语言指定。

未指定但与平台相关的是提供的整数类型的范围。如果范围满足C ++标准要求,charshort intintlong intlong long int都具有相同的范围符合标准为long long int。在这样的平台上,不会发生任何扩大或缩小,但签名的&lt; - &gt;无符号转换仍然可以改变值。