代码之家  ›  专栏  ›  技术社区  ›  fghoussen

在C结构体中,为什么打包、对齐似乎会进行填充?

  •  4
  • fghoussen  · 技术社区  · 9 月前

    在C结构体中,为什么 packed,aligned 似乎在填充?

    我必须使用i2c从远程设备读取一堆MSB/LSB字节。由于所有设备数据都是字节,我使用 uint8_t 其精确地表示8位,即1字节。

    现在我需要确定结构体是 packed (即结构中的元素之间没有“洞”),除非我不会读取远程设备中生成的数据。

    然后,我补充道 aligned 为了提高性能(即允许CPU以最小的内存访问量读取结构)。

    正如这里所解释的那样 Structure padding and packing ,填充将结构成员与“自然”地址边界对齐,并且,打包可防止填充。

    这个简单的测试让我很惊讶:

    $ gcc --version
    gcc (Debian 10.2.1-6) 10.2.1 20210110
    
    $ cat dumb.c 
    #include <stdio.h>
    #include <stdint.h> // uint8_t
    
    struct struct1 {
      uint8_t msb;
    } __attribute__((packed));
    
    struct struct2 {
      uint8_t msb;
    } __attribute__((packed,aligned(4)));
    
    struct struct3 {
      uint8_t msb;
      uint8_t lsb;
    } __attribute__((packed));
    
    struct struct4 {
      uint8_t msb;
      uint8_t lsb;
    } __attribute__((packed,aligned(4)));
    
    int main(void) {
      struct struct1 s1;
      printf("sizeof(s1) %zu\n", sizeof(s1));
      struct struct2 s2;
      printf("sizeof(s2) %zu\n", sizeof(s2));
      struct struct3 s3;
      printf("sizeof(s3) %zu\n", sizeof(s3));
      struct struct4 s4;
      printf("sizeof(s4) %zu\n", sizeof(s4));
      return 0;
    }
    
    $ gcc -o dumb dumb.c
    
    $ ./dumb 
    sizeof(s1) 1
    sizeof(s2) 4
    sizeof(s3) 2
    sizeof(s4) 4
    
    

    对齐的 似乎“填补了结构体的末尾”:这是意料之中的吗?

    • 我早料到 s2 从4字节的存储器地址开始,但大小为1。
    • 我早料到 s4 从4字节的存储器地址开始,但大小为2。

    我从远程设备读取这些字节,因此每个字节都使用i2c从设备传输到PC:现在为了性能,最好还是继续 拥挤的 只是为了避免“最后的额外填充”,或者,最好还是去 打包、对齐 每次传输时,都要传输和读取额外的未使用的“末尾填充”字节?

    2 回复  |  直到 9 月前
        1
  •  2
  •   dbush    9 月前

    这个 aligned a上的属性 struct 声明意味着结构体的任何实例都必须从对齐的地址开始。

    这也意味着,如果你有一个结构数组,该结构可能需要尾部填充,以便数组的每个成员都正确对齐。

    packed 属性将最小化结构中使用的任何填充,当与 对齐的 .

    例如,如果你有这样的声明:

    struct struct2 s2[2];
    

    如果你没有尾随填充,那么 s2[1] 不会正确对齐。

        2
  •  0
  •   Eric Postpischil    9 月前

    packed 说要把构件打包到结构内。

    aligned 通过在末尾填充来使对象对齐。

    推荐文章