未签名的签名转换

Som*_*ody 11 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::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
Run Code Online (Sandbox Code Playgroud)

我理解为什么"a"没有给出预期的结果.但为什么"b"和"c"失败让我感到困惑.对于"b",我认为在将"x"转换为"int"后,结果将再次为"int".

你能开导我吗?

编辑:编译器不应警告?g ++(Ubuntu/Linaro 4.4.4-14ubuntu5)4.4.5

谢谢,

Naw*_*waz 27

在算术运算中,如果任何操作数是unsigned,则另一个操作数转换为unsigned(如果是signed),并且操作的结果unsigned也是.

此外,铸造unsignedsigned,然后做的操作不改变操作数的位表示.在二进制补码架构(即几乎每个现代架构)上,(int)x具有相同的位表示x,只有在十进制系统中计算它们的时它们的解释才会发生变化.但重要的是,算术运算是在比特表示上进行的(而不是在十进制系统中的).并且由于转换不会改变位表示,结果的位表示也不会改变.

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

许多期望算术或枚举类型的操作数的二元运算符会以类似的方式引起转换并产生结果类型.目的是产生一个通用类型,它也是结果的类型.此模式称为通常的算术转换,其定义如下:

[...]

否则,如果任一操作数是无符号的,则另一个操作数应转换为无符号.


ken*_*ytm 11

像往常一样引用标准....

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

许多期望算术或枚举类型的操作数的二元运算符会以类似的方式引起转换并产生结果类型.目的是产生一个通用类型,它也是结果的类型.此模式称为通常的算术转换,其定义如下:

  • 如果任一操作数是类型long double,则另一个操作数应转换为long double.
  • 否则,如果任一操作数是double,则另一个操作数应转换为double.
  • 否则,如果任一操作数是float,则另一个操作数应转换为float.
  • 否则,应对两个操作数执行整体促销(4.5).54)
  • 然后,如果任一操作数是unsigned long另一个应转换为 unsigned long.
  • 否则,如果一个操作数是a long int和另一个unsigned int,那么如果a long int可以表示a的所有值unsigned int, unsigned int则应转换为a long int; 否则两个操作数都应转换为unsigned long int.
  • 否则,如果任一操作数是long,则另一个操作数应转换为long.
  • 否则,如果任一操作数是unsigned,则另一个操作数应转换为unsigned.

[注意:否则,唯一剩下的情况是两个操作数都是int]

基本上,它可以概括为

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

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