C++ 无符号到有符号的转换

C++ 无符号到有符号的转换,c++,C++,考虑以下几点: #include <iostream> int main() { unsigned int x = 3; unsigned int y = 5; std::cout << "a: " << x - y << std::endl; std::cout << "b: " << ((int)x) - y << std::endl; std:

考虑以下几点:

#include <iostream>

int main() {

    unsigned int x = 3;
    unsigned int y = 5;

    std::cout << "a: " << x - y        << std::endl;

    std::cout << "b: " << ((int)x) - y << std::endl;

    std::cout << "c: " << x - ((int)y) << std::endl;

    std::cout << "d: " << ((int)x) - ((int)y) << std::endl;

}

$ g++ -Wconversion -Wall uint_stackoverflow.cc -o uint_stackoverflow && ./uint_stackoverflow
a: 4294967294
b: 4294967294
c: 4294967294
d: -2
#包括
int main(){
无符号整数x=3;
无符号整数y=5;

std::cout在算术运算中,如果任何一个操作数
无符号
,另一个操作数将转换为
无符号
(如果其
有符号
),运算结果也将是
无符号

此外,将
无符号
强制转换为
有符号
,然后执行该操作不会改变操作数的位表示形式。在二补结构(即几乎所有现代结构)上,
(int)x
x
具有相同的位表示形式,只有在计算其十进制值时,它们的解释才会改变。但重要的一点是,算术运算是在位表示形式上执行的(而不是在其十进制值上执行的)。而且由于转换不会更改位表示,因此结果的位表示也不会更改

C++03标准在§5/9中规定:

许多二进制运算符 算术或枚举的操作数 类型原因转换和产量 结果类型以类似的方式 目的是产生一种普通类型, 这也是结果的类型。 这种模式被称为普通模式 算术转换,即 定义如下:

[……]

否则,如果任一操作数为 未签名的,另一个应转换 要取消签名


这是因为在执行隐式转换时存在数据类型的继承权,无符号整数的优先级高于有符号整数,因此b和c被转换回无符号整数,这就是为什么您看到的结果是无符号整数

如果你不确定类型,但知道你想要的结果类型,那么你应该像在d中一样同时施放x和y

这对类型转换有很好的解释:


像往常一样引用标准

对于C++98,§[expr]/9:

许多二进制运算符 算术或枚举的操作数 类型原因转换和产量 结果类型以类似的方式 目的是产生一种普通类型, 这也是结果的类型。 这种模式被称为普通模式 算术转换,即 定义如下:

  • 如果任一操作数的类型为长双精度
,则应转换另一个操作数 到
长双精度
  • 否则,如果任一操作数是双精度的,则应转换另一个操作数 到
    加倍
  • 否则,如果其中一个操作数是
    浮点
    ,则应转换另一个操作数 到
    浮动
  • 否则,应在两个平台上执行整体促销(4.5) 操作数(0.54)
  • 然后,如果其中一个操作数为无符号长,则另一个操作数应转换为
    unsigned long
  • 否则,如果一个操作数是长整数,另一个是无符号整数, 那么如果一个
    长int
    可以表示所有
    无符号int
    的值
    无符号整数
    应转换为
    long int
    ;否则两个操作数 应转换为
    无符号长
    int
  • 否则,如果任一操作数
    ,则应转换另一个操作数 到
  • 否则,如果任一操作数
    无符号
    ,则另一个操作数应为 已转换为未签名的
  • [注:否则,剩下的 情况是两个操作数都是
    int
    ]

    基本上可以概括为

    • long-double
      double
      float
      unsigned-long
      long
      unsigned
      int
    • (小于
      int
      的类型将转换为
      int

    在第5项之后,文本更改为C++0x(§[expr]/10),但对OP代码的影响是相同的:
    int
    将转换为
    无符号

    注意,将大的
    无符号
    转换为
    有符号
    显然是不可移植的。C++11标准规定:如果目标类型是有符号的,则如果源整数可以在目标类型中表示,则该值不会更改。否则,结果是实现定义的。"算术是在C中的值上执行的,而不是位表示本身。choose two的补码表示法的优点之一是,有符号算术可以使用与无符号算术相同的指令完成。这与强制转换是否更改表示法无关,但实际上,这必须在不要使用2的补码。在第一段中,最好明确你的意思是
    unsigned int
    ,而不是一般的无符号类型(例如,如果
    unsigned short
    short
    是操作数,那么它们将升级为
    int
    ,而不是任何无符号)