C ++整数溢出和升级

时间:2012-10-15 04:19:04

标签: c++ language-lawyer

  

可能重复:
  How do promotion rules work when the signedness on either side of a binary operator differ?

我正试图围绕C ++中的整数提升和溢出。我对以下几点感到困惑:

a)如果我有以下代码段:

int i = -15; 
unsigned j = 10; 
std::cout << i + j;

我出去了-5 % UINT_MAX。这是因为表达式i + j会自动提升为无符号吗?我试图阅读标准(4.13):

— The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.

我不确定我是否读错了,但如果这是真的,为什么i + j最终为无符号?

b)添加到上一段,我现在有:

int k = j + i;

即将评估为-5。是不是应该首先评估表达式j + i,在我的系统上给出4294967291,并将其设置为等于j?那应该是超出范围的,所以这种行为是不确定的?我不确定为什么会得到-5

c)如果我使用short稍微更改 a)中的细分,我有:

short i = -15;
unsigned short j = 10;
std::cout << i + j;

我想当我这样做时,我会得到与 a)相同的结果,只有-5 % USHRT_MAX。但是,当我执行此操作时,我得到-5。为什么使用short提供的值与int不同?

d)我一直都知道有符号整数的溢出行为是未定义的。例如:int r = ++INT_MAX将是未定义的。

但是,如果存在无符号溢出,则将定义数量。例如:unsigned a = ++UINT_MAX,则a为0。这是对的吗?

然而,该标准似乎没有任何关于它的说法。真的吗?如果是这样,为什么会这样?

1 个答案:

答案 0 :(得分:4)

a)来自§5/ 9:

  

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

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

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

因此,由于intjunsigned会提升为i,并且使用无符号整数运算执行加法。

b)这是UB。添加的结果是unsigned(按(a)),因此您在赋值中溢出unsigned int

c)来自§4.5/ 1:

  

intcharsigned charunsigned charshort int类型的左值可以转换为unsigned short int类型的右值如果int可以表示源类型的所有值;否则,源rvalue可以转换为int类型的右值。

因此,由于4字节unsigned int可以表示2字节intshort中的任何值,因此两者都会提升为unsigned short(根据§5.9'积分促销规则),然后添加为int s。

d)来自§3.9.1/ 4:

  

无符号整数,声明为int,应遵守算术模2 n 的定律,其中 n 是位数在特定大小的整数的值表示中。

因此,unsigned是合法的(不是UB)并且等于0。