Union and struct packing problem

无人久伴 提交于 2019-11-30 14:35:15

Your struct has only 31 bits

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:

#include <inttypes.h>
#include <stdio.h>

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;
        };
} page_union_t;

int main(void)
{
        page_union_t p = { .raw = 0 }; //.....
        unsigned trg_page = 0xA5A5A;
        unsigned user = 1;
        unsigned rw = 1;
        unsigned present = 1;

        p.frame = trg_page;
        p.user = user;
        p.rw = rw;
        p.present = present;

        printf("p.raw = 0x%08X\n", p.raw);

        p.raw = trg_page<<12 | user<<2 | rw<<1 | present;
        printf("p.raw = 0x%08X\n", p.raw);

        p.raw <<= 1;
        printf("p.raw = 0x%08X\n", p.raw);
        return(0);
}

produces the results shown:

p.raw = 0xE014B4B4
p.raw = 0xA5A5A007
p.raw = 0x4B4B400E

With the order of the fields reversed, the result is more nearly explicable:

#include <inttypes.h>
#include <stdio.h>

typedef union
{
        uint32_t raw;
        struct
        {
                unsigned int frame:20;
                unsigned int free:7;
                unsigned int dirty:1;
                unsigned int user:1;
                unsigned int rw:1;
                unsigned int present:1;
        };
} page_union_t;

int main(void)
{
        page_union_t p = { .raw = 0 }; //.....
        unsigned trg_page = 0xA5A5A;
        unsigned user = 1;
        unsigned rw = 1;
        unsigned present = 1;

        p.frame = trg_page;
        p.user = user;
        p.rw = rw;
        p.present = present;

        printf("p.raw = 0x%08X\n", p.raw);

        p.raw = trg_page<<12 | user<<2 | rw<<1 | present;
        printf("p.raw = 0x%08X\n", p.raw);

        p.raw <<= 1;
        printf("p.raw = 0x%08X\n", p.raw);
        return(0);
}

This gives the result:

p.raw = 0xA5A5A00E
p.raw = 0xA5A5A007
p.raw = 0x4B4B400E

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..

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.

For reference to anyone who might find this, try the packed attribute:

struct __attribute__((packed)){

}

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?

// maybe try this
page_union_t p = {0};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!