2017-01-18 88 views
1

所以我正在玩类型和我下面出现这个奇怪的结果。调试它没有意义,然后唯一的结果是检查出C++ spects,这没有太大的帮助。我想知道你是否可能完全知道这里发生了什么,如果它是32Bit和/或64Bit的特定问题。unsigned int/signed int/long long:莫名其妙的输出

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int u = 1; 
    signed int i = 1; 

    long long lu = -1 * u; 
    long long li = -1 * i; 

    std::cout<<"this is a weird " << lu << " " << li << std::endl; 

    return 0; 
} 

当输出是

this is a weird 4294967295 -1 
+3

@George这不是未定义的行为,因为这是无符号整数溢出 – DarthRubik

回答

5

关键的观察结果是表达-1 * uunsigned int类型。这是因为算术转换的规则说如果一个操作数是unsigned int而另一个是signed int,那么后面的操作数是转换成unsigned int。算术表达式最终只针对同类操作数定义,所以转换发生在操作正确之前。

-1转换为unsigned int的结果是一个很大的正数,表示为long long int,这是您在输出中看到的数字。

目前,这是[expr] /(11.5.3)。

+0

谢谢你Kerrek! –

+0

@ShanyG:我的荣幸:-) –

+0

@ShanyG:对于本质,我让Kerrek SB成为这个网站上最聪明的人。 Hans Passant同样在Windows C++的东西上。 – Bathsheba

1

-1 * i

的评价是二int类型的琐碎乘法:没什么可奇怪的存在。而long long必须能够容纳任何int


首先说明是有与在C++负字面没有这样的事情,所以

-1 * u

作为(-1) * u由于操作者的优先级进行评价。 (-1)的类型必须是int。但是,由于C++的参数转换规则,这将被转换为unsigned int,因为另一个参数是unsigned int这样做的话,它被模UINT_MAX + 1模转换,所以你最终以UINT_MAX乘以1,这是你观察到的数字,尽管转换为一个long long类型。

最后要注意,这个转换的行为是受到转换从unsignedsigned类型的规则:如果unsigned intlong long是你的平台上都为64位,则行为是实现定义的。

+1

现在我完成了,非常谦虚,并且在我退休时,会让您作为我公司的顾问前进。 – Bathsheba

+1

我期待收到未签署的合同:-) –

+0

我认为*(但仔细检查)转换回签名的方式永远不是UB;它是实现定义的。什么是UB就像签名类型的'a + b'。 –

1

-1的类型是signed int。当您在不同基本类型的对象之间执行算术运算时,一个或两个参数将被转换,以便两者具有相同的类型。 (对于非基本类型,混合操作数可能会有操作符重载)。在这种情况下,符号值将转换为无符号,遵循转换规则

因此,-1被转换为无符号。但负数不能用无符号类型表示。发生的情况是,结果值将是可以由无符号类型表示的最小正值,即与原始有符号值相匹配,并以无符号类型表示的最大值为模。哪个平台上正好是4294967295


规则([EXPR],标准草案):

...适用于非整数规则...

否则,积分优惠(4.5)应在两个operands.61进行再下面 规则应被施加到推动操作数:

- 如果两个操作数具有相同类型,则不需要进一步转换。 - 否则,如果两个操作数具有有符号整数类型或两者都具有无符号整数类型,则具有较小整数转换等级类型的 操作数应转换为具有更高等级的 操作数的类型。

- 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的 秩,用符号整型操作数须转换到 操作数与该类型无符号整数类型。 (适用于你的情况)

- 否则,如果有符号整数类型的操作数的类型,可以表示所有的 无符号整型操作数的类型的值,用无符号整型操作数应将 转换为带符号整数类型的操作数的类型。

- 否则,两个操作数将转换为无符号整数类型,对应于带有符号整数类型的操作数的 类型。

+0

一般来说,“其中一个参数将被转换为另一个类型”并不正确。一般而言,“这两个论点都可以转化为某种类型”。见[expr] /(11.5.5)。 –

+0

@KerrekSB谢谢,希望现在的措辞更好。 – user2079303

+0

这仍然不正确。转换的类型也可以被签名,例如,见[expr] /(11.5.4)。 –

0

当解释为32b有符号整数时,位模式“0xFFFFFFFF”对应于“-1”,当解释为32b无符号整数时,对应于“4294967295”。

  • 如果使用-2的结果是 “4294967294”
  • 如果使用-3的结果是 “4294967293”
  • 如果使用-4的结果是 “4294967292”
  • ....