在乘法的情况下,无符号数会被隐式转换为有符号数。
这是错误的。当一个int和unsigned int被用作乘法或除法运算符的操作数时,int参数会被转换为unsigned int。
这在C++17标准的第8p11节中有明确说明。
许多二元运算符期望算术或枚举类型的操作数,并以类似的方式进行转换并产生结果类型。其目的是产生一个公共类型,也是结果的类型。这种模式被称为“通常的算术转换”,定义如下:
(11.1) 如果任一操作数是作用域枚举类型(10.2),则不执行转换;如果另一个操作数的类型不同,则表达式是非法的。
(11.2) 如果任一操作数是long double类型,则另一个操作数应转换为long double类型。
(11.3) 否则,如果任一操作数是double类型,则另一个操作数应转换为double类型。
(11.4) 否则,如果任一操作数是float类型,则另一个操作数应转换为float类型。
(11.5) 否则,应对两个操作数执行整数提升(7.6)。然后,对提升后的操作数应用以下规则:
(11.5.1) 如果两个操作数具有相同的类型,则不需要进一步转换。
(11.5.2) 否则,如果两个操作数具有有符号整数类型或都具有无符号整数类型,则具有较低整数转换等级的操作数应转换为具有较高等级的操作数的类型。
(11.5.3) 否则,如果具有无符号整数类型的操作数的等级大于或等于另一个操作数的类型的等级,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
(11.5.4) 否则,如果具有有符号整数类型的操作数的类型能够表示无符号整数类型的所有值,则具有无符号整数类型的操作数应转换为具有有符号整数类型的操作数的类型。
(11.5.5) 否则,两个操作数应转换为与具有有符号整数类型的操作数的类型相对应的无符号整数类型。
上面加粗的部分是适用于这里的。
所以在这个表达中:
i *= u;
这相当于这个:
i = i * u;
变量 i
的值为 -100,被转换为一个 unsigned
值,假设是一个 32 位的 int
,其值为 4294967196。乘法操作导致了溢出,结果为 4294966296。然后将这个值转换回 int
并赋值给 i
。这个转换的结果是由具体实现定义的,尽管大多数实现会简单地将表示重新解释为 int
,从而得到值 -1000。
接下来,在这个表达式中:
i /= u;
这与这个相同。
i = i / u;
同样的转换与之前一样,所以
int
值-1000被转换为
unsigned
值4294966296。然后,除法的结果是429496629。这个值在
int
的范围内,所以在被赋值给
i
之前,它在转换为
int
时保持不变。