I'm writing some software where each bit must be exact(it's for the CPU) so __packed is very important.
typedef union{
uint32_t raw;
struct{
unsigned int present:1;
unsigned int rw:1;
unsigned int user:1;
unsigned int dirty:1;
unsigned int free:7;
unsigned int frame:20;
} __packed;
}__packed page_union_t;
that is my structure and union. It does not work however:
page_union_t p; //.....
//This:
p.frame=trg_page;
p.user=user;
p.rw=rw;
p.present=present;
//and this:
p.raw=trg_page<<12 | user<<2 | rw<<1 | present;
should create the same uint32. But they do not create the same thing.
Is there something I can not see that is wrong with my union?
For reference to anyone who might find this, try the packed attribute:
AFAIK, the order in which the bits in the struct are stored is undefined by the C99 standard (and the C89 standard too). Most likely, the bits are in the reverse order from what you expected.
You should have shown the result you got as well as the result you expected - it would help us with the diagnosis. The compiler you use and the platform you run on could also be significant.
On MacOS X 10.4.11 (PowerPC G4), this code:
produces the results shown:
With the order of the fields reversed, the result is more nearly explicable:
This gives the result:
The first result has an E as the last hex digit because the least significant bit is not used, because the bit-field structure has only 31-bits defined..
You don't mention that you are clearing out the bits of the structure beforehand, are you sure you aren't ending up with garbage bits left over in the first case?
Your struct has only 31 bits
If the exact position of bits matters, your safest bet is explicit packing and unpacking of the structure into an unsigned char array. Anything else is too implementation dependent.