It generally used to store character values. unsigned is a qualifier which is used to increase the values to be written in the memory blocks. For example - char can store values between -128 to +127, while an unsigned char can store value from 0 to 255 only.
The basic ASCII values are in range 0 to 127. The rest part of the ASCII is known as extended ASCII. Using char or signed char we cannot store the extended ASCII values. By using the unsigned char, we can store the extended part as its range is 0 to 255.
It is usually better to use char but it makes so little difference it does not matter. It's raw data so you should be simply passing it around as such rather than trying to work with it via char pointers of one type or another.
Signed char will have values ranging from -127 to +127. Whereas char (or unsigned char) will have values from 0 to 255. It is still useful to specify unsigned or signed, because the default can vary from compiler to compiler. Signed data types are basically a way to store and compute negative values.
In C the unsigned char
data type is the only data type that has all the following three properties simultaneously
if these are the properties of a "binary" data type you are looking for, you definitively should use unsigned char
.
For the second property we need a type that is unsigned
. For these all conversion are defined with modulo arihmetic, here modulo UCHAR_MAX+1
, 256
in most 99% of the architectures. All conversion of wider values to unsigned char
thereby just corresponds to truncation to the least significant byte.
The two other character types generally don't work the same. signed char
is signed, anyhow, so conversion of values that don't fit it is not well defined. char
is not fixed to be signed or unsigned, but on a particular platform to which your code is ported it might be signed even it is unsigned on yours.
You'll get most of your problems when comparing the contents of individual bytes:
char c[5];
c[0] = 0xff;
/*blah blah*/
if (c[0] == 0xff)
{
printf("good\n");
}
else
{
printf("bad\n");
}
can print "bad", because, depending on your compiler, c[0] will be sign extended to -1, which is not any way the same as 0xff
The plain char
type is problematic and shouldn't be used for anything but strings. The main problem with char
is that you can't know whether it is signed or unsigned: this is implementation-defined behavior. This makes char
different from int
etc, int
is always guaranteed to be signed.
Although VC gave the warning ... truncation of constant value
It is telling you that you are trying to store int literals inside char variables. This might be related to the signedness: if you try to store an integer with value > 0x7F inside a signed character, unexpected things might happen. Formally, this is undefined behavior in C, though practically you'd just get a weird output if attempting to print the result as an integer value stored inside a (signed) char.
In this specific case, the warning shouldn't matter.
EDIT :
In other related questions unsigned char is highlighted because it is the only (byte/smallest) data type which is guaranteed to have no padding by the C-specification.
In theory, all integer types except unsigned char and signed char are allowed to contain "padding bits", as per C11 6.2.6.2:
"For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter)."
"For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; signed char shall not have any padding bits."
The C standard is intentionally vague and fuzzy, allowing these theoretical padding bits because:
However, in the real world outside the C standard, the following applies:
So there is no real reason to use unsigned char or signed char just to dodge some theoretical scenario in the C standard.
Bytes are usually intended as unsigned 8 bit wide integers.
Now, char doesn't specify the sign of the integer: on some compilers char could be signed, on other it may be unsigned.
If I add a bit shift operation to the code you wrote, then I will have an undefined behaviour. The added comparison will also have an unexpected result.
char c[5], d[5];
c[0] = 0xF0;
c[1] = 0xA4;
c[2] = 0xAD;
c[3] = 0xA2;
c[4] = '\0';
c[0] >>= 1; // If char is signed, will the 7th bit go to 0 or stay the same?
bool isBiggerThan0 = c[0] > 0; // FALSE if char is signed!
printf("%s\n", c);
memcpy(d, c, 5);
printf("%s\n", d);
Regarding the warning during the compilation: if the char is signed then you are trying to assign the value 0xf0, which cannot be represented in the signed char (range -128 to +127), so it will be casted to a signed value (-16).
Declaring the char as unsigned will remove the warning, and is always good to have a clean build without any warning.
The signed-ness of the plain char
type is implementation defined, so unless you're actually dealing with character data (a string using the platform's character set - usually ASCII), it's usually better to specify the signed-ness explicitly by either using signed char
or unsigned char
.
For binary data, the best choice is most probably unsigned char
, especially if bitwise operations will be performed on the data (specifically bit shifting, which doesn't behave the same for signed types as for unsigned types).
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