The order does matter due to integer promotions.
When applying an arithmetic operator, each of its operands is first promoted to int
if its rank is less than int
(such as char
or short
). If one of those operands then has a higher rank still (such as long
), than the smaller is promoted.
From section 6.3.1 of the C standard:
2 The following may be used in an expression wherever an int or unsigned int may be used:
An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to
the rank of int and unsigned int.
A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions. All other types are unchanged by the integer
promotions.
From section 6.3.1.8:
If both operands have the same type, then no further conversion is
needed.
Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer
conversion rank is converted to the type of the operand with greater
rank.
Otherwise, if the operand that has unsigned integer type has rank
greater or equal to the rank of the type of the other operand, then
the operand with signed integer type is converted to the type of the
operand with unsigned integer type.
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, then the operand with unsigned integer type is converted
to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
As an example (assuming sizeof(int)
is 4 and sizeof(long)
is 8):
int i;
short s;
long l, result;
i = 0x10000000;
s = 0x10;
l = 0x10000000;
result = s * i * l;
printf("s * i * l=%lx\n", result);
result = l * i * s;
printf("l * i * s=%lx\n", result);
Output:
s * i * l=0
l * i * s=1000000000000000
In this example, s * i
is evaluated first. The value of s
is promoted to int
, then the two int
values are multiplied. At this point an overflow occurs unvoking undefined behavior. The result is then promoted to long
and multiplied by l
, with the result being of type long
.
In the latter case, l * i
is evaluated first. The value of i
is promoted to long
, then the two long
values are multiplied and an overflow does not occur. The result is then multiplied by s
, which is first promoted to long
. Again, the result does not overflow.
In a situation like this, I'd recommend casting the leftmost operand to long
so that all other operands are promoted to that type. If you have parenthesized subexpressions you may need to apply a cast there as well, depending on the result you want.