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 therefore char
is unsigned.
Either char
is then promoted to int
or unsigned int
and if it is promoted to an int
, then CHAR_MAX + 1
will necessarily fit into an int
too, and will not overflow, or if unsigned int
it may fit or wrap around to zero. When the resulting value, which is numerically either CHAR_MAX + 1
or 0
after modulo reduction, back to c
, after modulo reduction it will become 0, i.e. CHAR_MIN
Otherwise char
is signed, then if CHAR_MAX
is smaller than INT_MAX
, the result of CHAR_MAX + 1
will fit an int
, 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
and char
is signed, then char
is promoted to an int
, and CHAR_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 always 0
, 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,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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With