【问题标题】:Union and struct packing problem联合和结构包装问题
【发布时间】:2010-11-02 00:26:03
【问题描述】:

我正在编写一些软件,其中每个位都必须准确(用于 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。但他们创造的不是同一种东西。

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

【问题讨论】:

    标签: c struct unions packing


    【解决方案1】:

    你的结构只有 31 位

    【讨论】:

      【解决方案2】:

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

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


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

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

      产生显示的结果:

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

      将字段顺序颠倒,结果更接近于解释:

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

      这给出了结果:

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

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

      【讨论】:

        【解决方案3】:

        如果位的确切位置很重要,您最安全的选择是将结构显式打包和解包到无符号字符数组中。其他任何东西都太依赖于实现了。

        【讨论】:

        • 我想知道 C 标准的作者对允许以非常明确的布局定义结构和/或位字段的概念给予了什么样的考虑,认识到编译器可能会为指定的结构生成低效的代码字节顺序或打包与本机不匹配,但至少能够在匹配时生成高效代码(而不是必须始终生成调用用户例程以字节构建事物的低效代码)。
        【解决方案4】:

        对于可能找到此内容的任何人的参考,请尝试打包属性:

        struct __attribute__((packed)){
        
        }
        

        【讨论】:

          【解决方案5】:

          您没有提到您正在预先清除结构的位,您确定您没有在第一种情况下留下垃圾位吗?

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多