C ++隐式转换(有符号+无符号)

时间:2013-07-24 11:33:55

标签: c++ type-conversion unsigned-integer arithmetic-expressions

我理解,对于隐式转换,如果我们有一个无符号类型操作数和一个带符号类型的操作数,并且无符号操作数的类型与带符号操作数的类型相同(或更大),则带符号操作数将被转换为无符号。

所以:

unsigned int u = 10;  
signed int s = -8;

std::cout << s + u << std::endl;

//prints 2 because it will convert `s` to `unsigned int`, now `s` has the value
//4294967288, then it will add `u` to it, which is an out-of-range value, so,
//in my machine, `4294967298 % 4294967296 = 2`

我不明白 - 我读过如果签名操作数的类型比无符号操作数大:

  • 如果无符号类型中的所有值都适合较大的类型,则无符号操作数将转换为带符号类型

  • 如果无符号类型的值不适合较大的类型,则带符号的操作数将转换为无符号类型

所以在以下代码中:

signed long long s = -8;
unsigned int u = 10;
std::cout << s + u << std::endl;

u将转换为有符号long long,因为int值可以适合带符号的long long ??

如果是这种情况,在什么情况下较小的类型值不适合较大的类型?

3 个答案:

答案 0 :(得分:20)

标准的相关引用:

5个表达式[expr]

  

10许多期望算术或算术操作数的二元运算符   枚举类型导致转换并产生类似的结果类型   办法。目的是产生一种普通类型,它也是一种类型   结果。这种模式称为通常的算术转换,   其定义如下:

[省略了相同类型或类型的等号的2个条款]

  

- 否则,如果具有无符号整数类型的操作数具有等级   大于或等于另一个操作数类型的等级,   带有符号整数类型的操作数应转换为类型   带有无符号整数类型的操作数。

     

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

     

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

让我们在sizeof(int) < sizeof(long) == sizeof(long long) (很容易适应其他情况)的系统上考虑上述3个子句中的每一个的以下3个示例案例

#include <iostream>

signed int s1 = -4;
unsigned int u1 = 2;

signed long int s2 = -4;
unsigned int u2 = 2;

signed long long int s3 = -4;
unsigned long int u3 = 2;

int main()
{
    std::cout << (s1 + u1) << "\n"; // 4294967294
    std::cout << (s2 + u2) << "\n"; // -2 
    std::cout << (s3 + u3) << "\n"; // 18446744073709551614  
}
输出

Live example

第一个子句:等级的类型,因此signed int操作数被转换为unsigned int。这需要一个价值转换(使用二进制补码)给出te打印值。

第二个子句:签名类型具有更高的等级,并且(在此平台上!)可以表示无符号类型的所有值,因此无符号操作数转换为有符号类型,并得到-2

第三个子句:签名类型再次具有更高的等级,但是(在这个平台上!)不能代表无符号类型的所有值,因此两个操作数都转换为unsigned long long,并且在签名后的值转换之后操作数,你得到印刷值。

注意,当无符号操作数足够大时(例如在这些例子中为6),那么由于无符号整数溢出,最终结果将为所有3个例子提供2。

(已添加)请注意,在对这些类型进行比较时,会得到更多意外结果。让我们用<

考虑上面的例子1
#include <iostream>

signed int s1 = -4;
unsigned int u1 = 2;
int main()
{
    std::cout << (s1 < u1 ? "s1 < u1" : "s1 !< u1") << "\n";  // "s1 !< u1"
    std::cout << (-4 < 2u ? "-4 < 2u" : "-4 !< 2u") << "\n";  // "-4 !< 2u"
}

由于2u后缀明确unsigned u,因此适用相同的规则。结果可能不是你在比较 -4&lt; 2 用C ++写-4 < 2u ...

答案 1 :(得分:2)

signed int不适合unsigned long long。所以你将有这个转换: signed int - &gt; unsigned long long

答案 2 :(得分:0)

请注意,C ++ 11标准不会讨论更大或更小的类型,它会讨论排名更低或更高的类型。

考虑long intunsigned int的情况,其中两者都是32位。 long int的排名高于unsigned int,但由于long intunsigned int都是32位,long int无法代表所有值unsigned int

因此我们将讨论最后一个案例(C ++ 11:5.6p9):

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

这意味着long intunsigned int都将转换为unsigned long int