12

可能重复:
当二元运算符任一侧的符号不同时,提升规则如何工作?

我试图在 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)如果我从a)稍微使用更改段short,我有:

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

我想当我这样做时,我会得到与a)相同的结果,只是使用-5 % USHRT_MAX. 但是,当我执行此操作时,我得到-5. 为什么 usingshort给出的值与 不同int

d)我一直了解到有符号积分的溢出行为是未定义的。例如:int r = ++INT_MAX将是未定义的。

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

但是,该标准似乎没有说明任何内容。真的吗?如果是这样,那是为什么?

4

1 回答 1

4

a) 从第 5/9 节开始:

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

  • 如果任一操作数为 类型long double,则另一个应转换为long double
  • 否则,如果任一操作数为double,则另一个应转换为double
  • 否则,如果任一操作数为float,则另一个应转换为float
  • 否则,应在两个操作数上执行积分提升 (4.5)。
  • 然后,如果任一操作数是unsigned long另一个,则应转换为unsigned long.
  • 否则,如果一个操作数是 along int而另一个是unsigned int,则如果 along int可以表示 an 的所有值unsigned intunsigned int则应将 a 转换为 a long int;否则两个操作数都应转换为unsigned long int.
  • 否则,如果任一操作数为long,则另一个应转换为long
  • 否则,如果任一操作数为unsigned,则另一个应转换为unsigned

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

因此,因为jis unsignedi被提升为unsigned并且使用 unsigned int 算术执行加法。

b) 这是 UB。加法的结果是unsigned int(根据(a)),因此您int在分配中溢出。

c) 从第 4.5/1 节开始:

如果可以表示源类型的所有值,则可以将char, signed char, unsigned char,short int或类型unsigned short int的右值转换为类型的右值;否则,源右值可以转换为类型的右值。intintunsigned int

因此,由于 4 字节int可以表示 2 字节short或中的任何值unsigned short,因此两者都被提升为int(根据 §5.9 的整体提升规则),然后添加为ints。

d) 从第 3.9.1/4 节开始:

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

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

于 2012-10-15T05:21:17.180 回答