可能重复:
当二元运算符两边的签名不同时,促销规则如何工作?
我试图围绕整数提升和C++溢出.我对以下几点感到困惑:
a)如果我有以下代码段:
int i = -15;
unsigned j = 10;
std::cout << i + j;
Run Code Online (Sandbox Code Playgroud)
我出去-5 % UINT_MAX.这是因为表达式i + j会自动提升为unsigned吗?我试图阅读标准(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;
Run Code Online (Sandbox Code Playgroud)
正在接受评估-5.不应该j + i首先评估表达式,4294967291在我的系统上给出,并将其设置为等于j?那应该是超出范围的,所以这种行为是不确定的?我不知道为什么会这样-5.
c)如果我稍微改变a)的段short,我有:
short i = -15;
unsigned short j = 10;
std::cout << i + j;
Run Code Online (Sandbox Code Playgroud)
我想当我这样做时,我会得到与a)相同的结果,只是-5 % USHRT_MAX.但是,当我执行此操作时,我得到了-5.为什么使用short给出的价值不同于int?
d)我一直都知道有符号整数的溢出行为是不确定的.例如:int r = ++INT_MAX将是未定义的.
但是,如果存在无符号溢出,则将定义数量.例如:unsigned a = ++UINT_MAX,那么就是0.那是对的吗?
但是,该标准似乎没有任何关于它的说法.真的吗?如果是这样,为什么呢?
a)来自\xc2\xa75/9:
\n\n\n\n\n许多期望算术或枚举类型操作数的二元运算符会以类似的方式导致转换并产生结果类型。目的是产生一个通用类型,这也是结果的类型。这种模式称为通常的算术转换,其定义如下:
\n\n\n
\n\n- 如果任一操作数的类型为
\nlong double,则另一个应\n 转换为long double。- 否则,如果任一操作数为
\ndouble,则另一个应转换为double。- 否则,如果任一操作数为
\nfloat,则另一个应转换为float。- 否则,将对两个操作数执行积分提升 (4.5)。
\n- 然后,如果其中一个操作数是
\nunsigned long另一个,则应转换为unsigned long.- 否则,如果一个操作数是 a ,
\nlong int另一个是unsigned int,则如果 along int可以表示 an 的所有值unsigned int,则应unsigned int将 转换为 along int;否则两个操作数都应转换为unsigned long int。- 否则,如果任一操作数为
\nlong,则另一个应转换为long。- 否则,如果任一操作数为
\nunsigned,则另一个应转换为unsigned。[注意:否则,唯一剩下的情况是两个操作数都是
\nint]
因此,由于jis被提升为unsigned,并且使用 unsigned int 算术执行加法。iunsigned
b) 这是 UB。加法的结果是unsigned int(按照(a)),因此您int在赋值中溢出了。
c) 来自\xc2\xa74.5/1:
\n\n\n\n\n\n
char如果、signed char、unsigned char、short int、 或类型的右值unsigned short int可以表示源类型的所有值int,则可以将其转换为类型的右值;int否则,源右值可以转换为 类型的右值unsigned int。
因此,由于 4 字节int可以表示 2 字节short或中的任何值unsigned short,因此两者都会提升为int(根据 \xc2\xa75.9 的积分提升规则),然后添加为ints。
d) 来自\xc2\xa73.9.1/4:
\n\n\n\n\n声明的无符号整数应遵循模 2 n
\nunsigned的算术定律,其中n是该特定大小的整数的值表示中的位数。
因此,UINT_MAX+1是合法的(不是 UB)并且等于 0。