As the title says, I get a "weird" result when running the following code:
#include <stdio.h>
int main()
{
char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int* ptr = (unsigned int*)buff;
char a = (char)((*ptr << (0*8)) >> (3*8));
char b = (char)((*ptr << (1*8)) >> (3*8));
char c = (char)((*ptr << (2*8)) >> (3*8));
char d = (char)((*ptr << (3*8)) >> (3*8));
printf("0x%x\n", *ptr);
printf("0x%x\n", a);
printf("0x%x\n", b);
printf("0x%x\n", c);
printf("0x%x\n", d);
return 0;
}
Output:
0x40398917
0x40
0x39
0xffffff89
0x17
Why am I not getting 0x89
?
It's because your
char
variables are signed and they're undergoing sign extension when being promoted (upgraded to a wider type in this case). Sign extension is a way of preserving the sign when doing this promotion, so that-119
stays as-119
whether it's 8-bit, 16-bit or a wider type.You can fix it by explicitly using
unsigned char
since, in C at least, whetherchar
is signed or unsigned is implementation-specific. FromC11 6.2.5 Types /15
:Sign extension does not come into play for unsigned types because they're, ... well, unsigned :-)
char, by default, is signed - this means that numbers run from -128 to 127. Any number outside of that doesn't fit. If you changed
char
tounsigned char
, you will get the numbers you expect.Use
memcpy
not a castThis is not correct:
buff
does not point to an int object or array, so the cast(unsigned int*)buff
is not defined.The safe way to reinterpret
buff
as anunsigned int
is withmemcpy
:When using
memcpy
, you have no make sure the bit representation you copy is valid for the destination type, of course.One portable but degenerate way to do that is to check that the representation matches an existing object (beware, the following is silly code):
This code uses
memcpy
and has fully defined behavior (even if useless). OTOH, the behavior ofis not defined, because
null_bytes
is not the address of anint
orunsigned int
.