C++中奇怪的有符号/无符号整数除法

6
int main(int argc, char *argv[]) {
    int i = -100;
    unsigned u = 10;

    cout << "i = " << i << endl;

    i *= u;
    cout << "i*10 = " << i << endl;

    i /= u;
    cout << "i = " << i << endl;

    return 0;
}

如果输出结果不是这样的话,我就不会在这里提出这个问题了。
i = -100
i*10 = -1000
i = 429496629

在乘法的情况下,无符号数会被隐式转换为有符号数。到目前为止,一切都好。
然而,在除法的情况下,有符号数会被隐式转换为无符号数,执行无符号除法,然后再转换回有符号数。
有人知道为什么会发生这种情况吗?因为对我来说这毫无意义。
附言:通过显式类型转换可以实现预期的行为:i /= (int) u;

4
C&C++是两种不同的编程语言;你实际上是在问哪一种? - undefined
1
我问这两个问题,因为C和C++的行为是相同的。示例代码是用C++给出的,但在C中也可以实现相同的结果(只需将cout替换为printf)。 - undefined
4
不要在同一篇帖子中提出两个不同的问题。因为这些问题的答案受到完全不同的规范限制。 - undefined
4
在乘法的情况下,无符号数会被隐式转换为有符号数。目前为止,一切都很好。不,实际上,在乘法的情况下,整数会被隐式转换为无符号数。然后,该结果会作为赋值的一部分被转换为整数。 - undefined
我甚至不确定整数提升的规则是否完全相同。但是在进行除法运算之前,你的有符号整数会被隐式转换为无符号整数。长话短说,不要让编译器为你隐式转换类型(也不要混合使用有符号和无符号类型)。 - undefined
显示剩余2条评论
1个回答

15
在乘法的情况下,无符号数会被隐式转换为有符号数。
这是错误的。当一个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时保持不变。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接