乘以无符号短会导致未定义的行为吗?

Does multiplying unsigned short cause undefined behaviour?

作为“”

的后续

我在问自己是否将等级低于 int 的所有类型(某些例外情况除外)提升为 int 以执行算术运算在某些情况下可能会导致 UB。

例如:

unsigned short a = 0xFFFF;
unsigned short b = a*a;

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

unsigned short a = 0xFFFF;
unsigned short b = (int)a*(int)a;

因为 (int)0xFFFF*(int)0xFFFF 会导致溢出,而​​有符号类型的溢出是 UB:可以将两个无符号短整数相乘 x,yx*y > INT_MAX 的情况下导致未定义的行为


更新

该题专门针对int为32位,short为16位的情况。

当你乘以 unsigned short * unsigned short 然后有一个 implicit conversion and the value is casted to int in C++11. The documentation 说:

Prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int as arguments

所以它会导致未定义的行为。

C++11 §3.9.1/4,完整引用:

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.

除了关于“已声明 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,(216−1) 2 = 232−2×216+1 > 231−1,其中最后一个值是最大正值 int