联合和结构包装问题

我正在编写一些软件,其中每个位必须精确(它是CPU的),所以__packed非常重要。

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; 

那是我的结构和结合。 但它不起作用:

 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; 

应该创建相同的uint32。 但他们并没有创造同样的东西。

有什么我看不出我的工会有问题吗?

你的结构只有31位

AFAIK,结构中的位的存储顺序由C99标准(以及C89标准)定义。 最有可能的是,这些位的顺序与您的预期相反。

您应该已经显示了您获得的结果以及您期望的结果 – 这将有助于我们进行诊断。 您使用的编译器和您运行的平台也可能很重要。


在MacOS X 10.4.11(PowerPC G4)上,此代码:

 #include  #include  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); } 

产生显示的结果:

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

随着字段顺序的颠倒,结果更加可以解释:

 #include  #include  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); } 

这给出了结果:

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

第一个结果有一个E作为最后一个hex数字,因为没有使用最低有效位,因为位域结构只定义了31位。

如果位的确切位置很重要,那么最安全的选择是显式打包并将结构解压缩到unsigned char数组中。 其他任何东西都与实现有关。

有关可能找到此内容的任何人的参考,请尝试packed属性:

 struct __attribute__((packed)){ } 

你没有提到你事先清理了结构的各个部分,你确定你没有在第一种情况下留下垃圾比特吗?

 // maybe try this page_union_t p = {0};