If char
is signed, then performing arithmetic on a byte value with the high bit set will result in sign extension when promoting to int
; so, for example:
char c = '\xf0';
int res = (c << 24) | (c << 16) | (c << 8) | c;
will give 0xfffffff0
instead of 0xf0f0f0f0
. This can be avoided by masking with 0xff
.
char
may still be preferable if you're interfacing with libraries that use it instead of unsigned char
.
Note that a cast from char *
to/from unsigned char *
is always safe (3.9p2). A philosophical reason to favour unsigned char
is that 3.9p4 in the standard favours it, at least for representing byte arrays that could hold memory representations of objects:
The object representation of an object of type T
is the sequence of N
unsigned char
objects taken up by the object of type T
, where N
equals sizeof(T)
.