Reputation: 2954
I wrote a struct with anonymous struct and uninon:
byte is typedef unsigned char byte
struct dns_flags
{
union
{
struct
{
byte QR : 1;
byte opCode : 4;
byte AA : 1;
byte TC : 1;
byte RD : 1;
byte RA : 1;
byte zero : 3;
byte rcode : 4;
};
uint16_t flagsValue;
};
};
Which represents DNS protocol flags.
I used #pragma pack(push,1)
and while sizeof(dns_flags) == 2
when flagsValue == 0x8180
; then rcode = 8
. So I wonder about the layout of the struct in memory: The rcode
nibble is the higher one?! that just doesn't make any sense... working with VS2012
Guy
Upvotes: 0
Views: 434
Reputation: 129314
The actual order of bitfields isn't specified in the standard. It is entirely up to the compiler to do what it likes (as long as it does it the same way each time). I think most compilers follow the byte-order of the machine itself (so the first field is the lowest bit in a little endian machine, and the highest bit in a big endian machine), but this is not guaranteed, just "convention".
Upvotes: 3
Reputation: 5315
I don't know what standard mandates, you can refer to Mats Peterson's answer, but this is how memory is layed out for this struct.
It is because your machine is little Endian and the value 0x8180
gets stored as 8081
i.e. lower byte is 0x80
at lower address and higher byte is 0x81
at higher address.
(LB)
(0x80) bytes (7->0) = 0x80
(HB)
(0x81) bytes (15->8) = 0x81
This forms your lower byte (0x80)
byte QR : 1; <------- Lower Address --> ( bit 0)
byte opCode : 4; --> ( bits 1,2,3,4)
byte AA : 1; --> ( bit 5)
byte TC : 1; --> ( bit 6)
byte RD : 1; --> ( bit 7)
And this is the higher byte (0x81)
byte RA : 1; --# (bit 8)
byte zero : 3; --# (bits 9,10,11)
byte rcode : 4; <------- Higher Address --# (bits 12,13,14,15)
If you check the value of RA
it should be one because it is at bit position 8
and 8th
bit in 0x8180
is 1
(converted to int
type).
And it the value written is 0x8280
then RA
will have value 0
and zero
will have 1
.
Upvotes: 2
Reputation:
Do not use bit fields in a union to address bits of an unsigned integer (the implementation has compiler and machine dependencies). A compatible solution:
struct dns_flags {
uint16_t flagsValue;
uint16_t qr() const { return flagsValue & 1; }
...
};
Upvotes: 3