unsigned long long x;
unsigned int y, z;
x = y*z;
The evaluation of the expression y*z
is not affected by the context in which it appears. It multiplies two unsigned int
values, yielding an unsigned int
result. If the mathematical result cannot be represented as an unsigned int
value, the result will wrap around. The assignment then implicitly converts the (possibly truncated) result from unsigned int
to unsigned long long
.
If you want a multiplication that yields an unsigned long long
result, you need to explicitly convert one or both of the operands:
x = (unsigned long long)y * z;
or, to be more explicit:
x = (unsigned long long)y * (unsigned long long)z;
C's *
multiplication operator applies only to two operands of the same type. Because of this, when you give it operands of different types, they're converted to some common type before the multiplication is performed. The rules can be a bit complex when you're mixing signed and unsigned types, but in this case if you multiply an unsigned long long
by an unsigned int
, the unsigned int
operand is promoted to unsigned long long
.
If unsigned long long
is at least twice as wide as unsigned int
, as it is on most systems, then the result will neither overflow nor wrap around, because, for example, a 64-bit unsigned long long
can hold the result of multiplying any two 32-bit unsigned int
values. But if you're on a system where, for example, int
and long long
are both 64 bits wide, you can still have overflow wraparound, giving you a result in x
that's not equal to the mathematical product of y
and z
.