It makes no difference whether you write a cast or not, in this situation. The issue is conversion of a char
to an int
. In C, there is implicit conversion between these two types: you can just assign one to the other without a cast, and a conversion happens. A cast is an explicit conversion. In other words, i = c;
and i = (char)c;
are exactly the same.
To understand the conversion, it seems easier to me to think in terms of values, rather than representations, sign extension, etc. etc.
When you write i = c;
, it means that the value of i
should be the same as the value of c
. If c
was -4
then i
will also be -4
, regardless of which bits are set in memory to represent this.
This always works, because all possible char
values are also valid int
values.
However when you go c = i;
you may find that i
has a value that is not a valid char
. For example if your compiler gives char
a range of [-128, 127]
(this is common, but not the only possibility), and i
had a value of 150
, then it is out of range.
When you assign an out-of-range value , what happens depends on whether the target type is signed or not.
- If your
char
s are unsigned
, then the value is adjusted modulo CHAR_MAX+1
until it is in range
- If your
char
s are signed
then the behaviour is implementation-defined.
The latter means that the compiler must document what happens. It is also permitted to raise a signal (similar to a segfault occurring, if you're not familiar with signals).
On typical systems, the compiler will take the lower 8 bits of 2's complement representation, but this is certainly not something you should rely on; in order to write robust code, you should avoid triggering this operation.
You can inspect the ranges for your types by doing #include <limits.h>
, and looking at CHAR_MIN
, CHAR_MAX
. (Those can be output via printf("%d, CHAR_MIN);
etc.)