The expression ++a
increments a
in the context of its type (8-bit unsigned) so wraps around to zero.
The expression a + 1
adds the 8-bit unsigned a
to the literal 1
(which is an int
) and, when you do that with disparate types, the smaller of them is usually "upgraded" to the other before adding. Hence you're then adding the two int
values, 255
and 1
, with no wrapping.
This is known in C as the "usual arithmetic conversions" and the section of the standard that deals with it, C11 6.3.1.8
, begins:
Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result.
After going through some floating point types, the following dictates how integral types are handled:
Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
- 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.
You may think that it's the fourth bullet point that comes into play here but, in actual fact, it's the preamble combined with the first bullet point. The "integer promotions", detailed in C11 6.3.1.1
, will actually take integral types of lesser or equal rank to int
and turn them into an int
(assuming that can represent all values of the original type, otherwise it makes it unsigned int
).
The other difference, of course, is that the first one modifies a
but the second one does not.