Is there anyone can help me to explain what is the difference between unsigned char and char in XOR operation?
#include <stdio.h>
int main() {
char a[2] = { 0x56, 0xa5 }; // a[0] 0101 0110
// a[1] 1010 0101
a[0] = a[0] ^ a[1]; // a[0] 1111 0011 f3
printf("%02x", a[0]);
puts("");
unsigned char b[2] = { 0x56, 0xa5 }; // b[0] 0101 0110
// b[1] 1010 0101
b[0] = b[0] ^ b[1]; // b[0] 1111 0011 f3
printf("%02x", b[0]);
puts("");
}
result:
fffffff3
f3
[Finished in 0.0s]
Another example:
#include <stdio.h>
int main() {
char a[2] = { 0x01, 0x0a };
a[0] = a[0] ^ a[1];
printf("%02x", a[0]);
puts("");
unsigned char b[2] = { 0x01, 0x0a };
b[0] = b[0] ^ b[1];
printf("%02x", b[0]);
puts("");
}
result:
0b
0b
[Finished in 0.0s]
In the first case, your code
printf("%02x", a[0]);
Passes a char
value to a variadic function printf
. The char
value is promoted to int
type and passed as such. The value of a[0]
is -13
because the char
type happens to be signed by default on your environment, The value is preserved by the promotion as int
and printf receives it as an int
.
The format %02x
expects an unsigned int
value. printf
was passed an int
value, an incorrect type invoking undefined behavior. Since int
and unsigned int
use the same parameter passing convention on your platform, this negative value of -13
is interpreted as an unsigned int
with the same bit pattern, with value 0xFFFFFFF3
because the int
on your platform has 32 bits and negative values are represented in 2s complement. The string produced by printf is fffffff3
. This behavior is not actually guaranteed by the C Standard.
In the second example, b[0]
is an unsigned char
with value 243
(0xf3
). Its promotion to int
preserves the value and the int
passed to printf
is 243
. The same undefined behavior is invoked as printf
is passed an int
instead of an unsigned int
. In your particular case, the conversion performed by printf
yields the same value, which printed as hex with at least 2 digits padded with leading 0
s gives f3
.
To avoid this ambiguity, you should either cast the operand as unsigned char
:
printf("%02x", (unsigned)(unsigned char)a[0]);
Or specify its actual type as unsigned char
:
printf("%02hhx", (unsigned char)a[0]);