My code:
#include <stdio.h>
#include <limits.h>
int main()
{
char c = CHAR_MAX;
c += 1;
printf("CHAR_MIN=%d CHAR_MAX=%d c=%d (%c)\n", CHAR_MIN, CHAR_MAX, c, c);
}
Output:
CHAR_MIN=-128 CHAR_MAX=127 c=-128 ()
We see that when we increment a char
variable set to CHAR_MAX
, it wraps around to CHAR_MIN
. Is this behavior guaranteed? Or is it going to be undefined behavior or implementation-specified behavior? What does the C99 standard say about this?
[Note: What happen when give value bigger than CHAR_MAX (127) to char or C- why char c=129 will convert into -127? does not address this question because they talk about assigning an out-of-range value not incrementing a value to an out-of-range value.]
The question is twofold: Firstly, is
char c = CHAR_MAX;
c += 1;
evaluated differently from
char c = CHAR_MAX;
c = c + 1;
and the answer is no it is not, because C11/C18 6.5.16.2p3:
- A compound assignment of the form
E1 op = E2
is equivalent to the simple assignment expressionE1 = E1 op (E2)
except that the lvalueE1
is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation. IfE1
has an atomic type, compound assignment is a read-modify-write operation withmemory_order_seq_cst
memory order semantics. 113)
Then, the question is what happens in c = c + 1
. Here the operands to +
undergo usual arithmetic conversions, and c
and 1
are therefore promoted to int
, unless a really wacky architecture requires that char
is promoted to unsigned int
. The calculation of +
is then evaluated, and the result, of type int
/unsigned int
is converted back to char
and stored in c
.
There are 3 implementation-defined ways in which this can then be evaluated:
CHAR_MIN
is 0 and thereforechar
is unsigned.Either
char
is then promoted toint
orunsigned int
and if it is promoted to anint
, thenCHAR_MAX + 1
will necessarily fit into anint
too, and will not overflow, or ifunsigned int
it may fit or wrap around to zero. When the resulting value, which is numerically eitherCHAR_MAX + 1
or0
after modulo reduction, back toc
, after modulo reduction it will become 0, i.e.CHAR_MIN
Otherwise
char
is signed, then ifCHAR_MAX
is smaller thanINT_MAX
, the result ofCHAR_MAX + 1
will fit anint
, and the standard C11/C18 6.3.1.3p3 applies to the conversion that happens upon assignment:- Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
Or, iff
sizeof (int) == 1
andchar
is signed, thenchar
is promoted to anint
, andCHAR_MAX == INT_MAX
=>CHAR_MAX + 1
will cause an integer overflow and the behaviour will be undefined.
I.e. the possible results are:
If
char
is an unsigned integer type, the result is always0
, i.e.CHAR_MIN
.Otherwise
char
is a signed integer type, and the behaviour is implementation-defined/undefined:CHAR_MIN
or some other implementation-defined value,- an implementation-defined signal is raised, possibly terminating the program,
- or the behaviour is undefined on some platforms where
sizeof (char) == sizeof (int)
.
All increment operations c = c + 1
, c += 1
, c++
and ++c
have the same side effects on the same platform. The evaluated value of the expression c++
will be the value of c
before the increment; for the other three, it will be the value of c
after the increment.