可能重复:
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
。这是对的吗?
然而,该标准似乎没有任何关于它的说法。真的吗?如果是这样,为什么会这样?
答案 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
]
因此,由于int
为j
,unsigned
会提升为i
,并且使用无符号整数运算执行加法。
b)这是UB。添加的结果是unsigned
(按(a)),因此您在赋值中溢出unsigned int
。
c)来自§4.5/ 1:
int
,char
,signed char
,unsigned char
或short int
类型的左值可以转换为unsigned short int
类型的右值如果int
可以表示源类型的所有值;否则,源rvalue可以转换为int
类型的右值。
因此,由于4字节unsigned int
可以表示2字节int
或short
中的任何值,因此两者都会提升为unsigned short
(根据§5.9'积分促销规则),然后添加为int
s。
d)来自§3.9.1/ 4:
无符号整数,声明为
int
,应遵守算术模2 n 的定律,其中 n 是位数在特定大小的整数的值表示中。
因此,unsigned
是合法的(不是UB)并且等于0。