Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c structs and byte setting/ ordering

Tags:

c

Hi I'm trying to read a byte array into a struct and the bytes are coming out in the reverse order (to how i expected). Can someone help me understand whats happening please?

unsigned char buf[] = {
0x11, 0x22, 0x33, 0x44,
0x55, 0x66, 0x77, 0x88,
0x99, 0xaa, 0xbb, 0xcc
};


typedef struct mystruct {
 uint16_t var1;
 uint16_t var2;
 uint32_t var3;
 uint32_t var4;
} something;


int main(int argc,char **argv){

   printf("sizeof buf: %lu %d \n",sizeof(buf),sizeof(something));
   something *st = (something*)&(buf[0]);
   #define pr(a) printf(#a" %x\n",a)
   pr(st->var1);
   pr(st->var2);
   pr(st->var3);
   pr(st->var4);

   return(0);
}

Output:

sizeof buf: 12 12 
st->var1 2211
st->var2 4433
st->var3 88776655
st->var4 ccbbaa99

I was expecting something like: st->var1 1122

Doing this also seems to output the same thing?

memcpy(&st->var1,buf,2);
pr(st->var1);

output: st->var1 2211

x86/Linux server, gcc version 4.5.3 (if that helps)

Thanks for your help.

like image 493
dave Avatar asked Jul 26 '13 11:07

dave


2 Answers

If you read about endianness, you will see that there are two ways of storing data longer than one byte in memory.

For big-endian systems (like ARM), the integer value 0x1122 is stored in memory as (from lower to higher addresses) 0x11 0x22. On a little-endian system (like x86) it's stored as 0x22 0x11.

As your data in the array is stored "big-endian", you get the opposite byte ordering to what you expect on a little-endian system like yours.

like image 51
Some programmer dude Avatar answered Sep 21 '22 21:09

Some programmer dude


As others have pointed out your main observable issue is that one of edianness.

Your method for accessing buf is undefined behavior because it violates strict aliasing rules here by type punning here:

something *st = (something*)&(buf[0]);

If I built this code on using gcc using the following arguments:

-O3 --Wstrict-aliasing=2

I receive the following warning:

main.cpp:22:4: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    something *st = (something*)&(buf[0]);
    ^

I am currently using version 4.8. The relevant section from the C11 draft standard that covers aliasing rules is 6.5/7.

like image 37
Shafik Yaghmour Avatar answered Sep 21 '22 21:09

Shafik Yaghmour