You are seeing the ffffff
because char
is signed on your system. In C, vararg functions such as printf
will promote all integers smaller than int
to int
. Since char
is an integer (8-bit signed integer in your case), your chars are being promoted to int
via sign-extension.
Since c0
and 80
have a leading 1-bit (and are negative as an 8-bit integer), they are being sign-extended while the others in your sample don't.
char int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061
Here's a solution:
char ch = 0xC0;
printf("%x", ch & 0xff);
This will mask out the upper bits and keep only the lower 8 bits that you want.
Here's a small program that illustrates the problem I think you might be having:
#include <stdio.h>
int main(void) {
char arr[] = { 0, 16, 127, 128, 255 };
for (int i = 0; i < sizeof arr; i ++) {
printf(" %2x", arr[i]);
}
putchar('\n');
return 0;
}
On my system (on which plain char
is signed), I get this output:
0 10 7f ffffff80 ffffffff
The value 255
, when stored in a (signed) char
, is stored as -1
. In the printf
call, it's promoted to (signed) int
-- but the "%2x"
format tells printf
to treat it as an unsigned int
, so it displays fffffffff
.
Make sure that your mesg
and mesg_check
arrays are defined as arrays of unsigned char
, not plain char
.
UPDATE: Rereading this answer more than a year later, I realize it's not quite correct. Here's a program that works correctly on my system, and will almost certainly work on any reasonable system:
#include <stdio.h>
int main(void) {
unsigned char arr[] = { 0, 16, 127, 128, 255 };
for (int i = 0; i < sizeof arr; i ++) {
printf(" %02x", arr[i]);
}
putchar('\n');
return 0;
}
The output is:
00 10 7f 80 ff
An argument of type unsigned char
is promoted to (signed) int
(assuming that int
can hold all values of type unsigned char
, i.e., INT_MAX >= UCHAR_MAX
, which is the case on practically all systems). So the argument arr[i]
is promoted to int
, while the " %02x"
format requires an argument of type unsigned int
.
The C standard strongly implies, but doesn't quite state directly, that arguments of corresponding signed and unsigned types are interchangeable as long as they're within the range of both types -- which is the case here.
To be completely correct, you need to ensure that the argument is actually of type unsigned int
:
printf("%02x", (unsigned)arr[i]);
Best Answer
The reason why this is happening is that
char
s on your system are signed. When you pass them to functions with variable number of arguments, such asprintf
(outside of fixed-argument portion of the signature)char
s get converted toint
, and they get sign-extended in the process.To fix this, cast the value to
unsigned char
:Demo.