Guy L
Guy L

Reputation: 2954

Struct with bit fields reordering?

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

Answers (3)

Mats Petersson
Mats Petersson

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

Uchia Itachi
Uchia Itachi

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

user2249683
user2249683

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

Related Questions