乘以unsigned short会导致未定义的行为吗?

Sim*_*mer 7 c++ types casting integer-promotion c++11

作为" /sf/ask/2361242901/ " 的后续行动

我问自己,如果促进所有类型(除了一些例外),以较低的排名比intint进行算术运算可能导致UB在某些情况下.

例如:

unsigned short a = 0xFFFF;
unsigned short b = a*a;
Run Code Online (Sandbox Code Playgroud)

由于unsigned short被提升为int算术运算,这将导致:

unsigned short a = 0xFFFF;
unsigned short b = (int)a*(int)a;
Run Code Online (Sandbox Code Playgroud)

因为(int)0xFFFF*(int)0xFFFF导致溢出,并且有符号类型的溢出是UB:可以将两个无符号短路相乘x,y导致未定义的行为x*y > INT_MAX


更新:

该问题专门针对的int是32位且short为16位的情况.

Che*_*Alf 7

C++11§3.9.1/ 4,完整报价:

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

除了关于"声明unsigned" 的略微误导的措辞之外,这似乎适用于每个只涉及某些给定无符号类型的参数的算术表达式,将产生该模型的模2 n的结果.

但是,对于低转换级别的无符号类型,根本没有算术表达式int:明显此类表达式中的所有参数至少转换为(1)int,或者取决于C++实现的数字范围,最多为unsigned int.

因此,a*b在哪里abunsigned short值,(2)可以有正式的未定义行为.因为它不是unsigned short表达.它(在实践中)是一种int表达方式.

也就是说,使用合理的编译器,它不会引入特殊的外壳,它会注意到正式的UB,并且实际上有8位字节和unsigned short最大值可以表示int,并且通用二进制补码有符号整数表示,结果,当转换回来时下来unsigned short,就好像是模数运算一样unsigned short.这是因为在机器代码级别,两个补码只是模数运算,范围以0为中心.


(1)在实践中,通常会使用每字节8位的实现,其中最大值unsigned short恰好在该int范围内,因此在实践中我们正在讨论转换为int.
(2)例如,对于16位unsigned short和32位int,(2 16 -1)2 = 2 32 -2×2 16 +1> 2 31 -1,其中最后一个值是最大正值int.

  • @Alf规范的例子是对有符号整数优化`x + 1> x`为'true`.由[`-fstrict-overflow`](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)控制,这是GCC的`-O2`的一部分.另请参阅LLVM博客上的[每个C程序员应该了解的未定义行为#2/3](http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html) . (2认同)