10

作为“ https://stackoverflow.com/questions/33732041/why-static-castunsigned-intushrt-maxushrt-max-yields-correct-value ”的后续行动

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;

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


更新

该问题专门针对int32 位和short16 位的情况。

4

2 回答 2

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

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

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

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

结果,a*bwhereabareunsigned 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

于 2015-11-16T10:09:03.647 回答
3

当您相乘时unsigned short * unsigned short,会有一个隐式转换,并且该值int在 C++11 中被强制转换为。文档说:

小整数类型(如 char)的纯右值可以转换为较大整数类型(如 int)的纯右值。特别是,算术运算符不接受小于 int 的类型作为参数

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

于 2015-11-16T10:08:10.393 回答