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 wouldn’t be asking the question here, if the output hadn’t been:
i = -100
i*10 = -1000
i = 429496629
- In the case of multiplication, unsigned is implicitely converted to signed. So far, so good.
- However, In the case of division, signed is implicitely converted to unsigned, unsigned division performed; then converted back to signed.
Does anyone have any idea why this is happening? Because it does not make any sence to me.
P.S. The expected behavior is achieved by explicit typecast: i /= (int) u;
>Solution :
In the case of multiplication, unsigned is implicitely converted to signed.
That is false. When an int and unsigned int are used as operands to either the * operator or the / operator , the int argument is converted to unsigned int.
This is spelled out in section 8p11 of the C++17 standard :
Many binary operators that expect operands of arithmetic or
enumeration type cause conversions and yield result types in a similar
way. The purpose is to yield a common type, which is also the type of
the result. This pattern is called the usual arithmetic conversions,
which are defined as follows:
- (11.1) If either operand is of scoped enumeration type (10.2), no conversions are performed; if the other operand does not have the same
type, the expression is ill-formed.- (11.2) If either operand is of type long double, the other shall be converted to long double.
- (11.3) Otherwise, if either operand is double, the other shall be converted to double.
- (11.4) Otherwise, if either operand is float, the other shall be converted to float.
- (11.5) Otherwise, the integral promotions (7.6) shall be performed on both operands. Then the following rules shall be applied to the
promoted operands:
- (11.5.1) If both operands have the same type, no further conversion is needed.
- (11.5.2) Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser
integer conversion rank shall be converted to the type of the operand
with greater rank.- (11.5.3) Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other
operand, the operand with signed integer type shall be converted to
the type of the operand with unsigned integer type.- (11.5.4) Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with
unsigned integer type, the operand with unsigned integer type shall be
converted to the type of the operand with signed integer type.- (11.5.5) Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with
signed integer type.
The section in bold above is what applies here.
So in this expression:
i *= u;
Which is equivalent to this:
i = i * u;
The value of i which is -100 is converted to an unsigned value which (assuming a 32 bit int) is 4294967196. The multiplication causes wraparound which results in 4294966296. This value is then converted to int when assigned back to i. This conversion is implementation defined although most implementations will simply reinterpret the representation as int which will result in the value -1000.
Then in this expression:
i /= u;
Which is the same as this:
i = i / u;
The same conversion happens as before, so the int value -1000 is converted to the unsigned value 4294966296. The result of the division is then 429496629. This value is in the range of an int, so it is assigned directly back to i without conversion.