在C结构体中,为什么
packed,aligned
似乎做了填充?
我必须使用 i2c 从远程设备读取一堆 MSB/LSB 字节。由于所有设备数据都是字节,因此我使用
uint8_t
来表示 8 位,即 1 个字节。
现在我需要确保该结构是
packed
(即结构中的元素之间没有“洞”),除非我不会读取远程设备中生成的数据。
然后,我添加了
aligned
以提高性能(即允许 CPU 以最少的内存访问来读取结构)。
如此处所述结构填充和打包,填充将结构成员与“自然”地址边界对齐,并且打包可防止填充。
这个简单的测试让我感到惊讶:
$ 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
aligned
似乎“填充了结构的末尾”:这是预期的吗?
s2
会从 4 字节的倍数内存地址开始,但是大小为 1。s4
会从 4 字节的倍数内存地址开始,但是大小为 2。我从远程设备读取这些字节,因此每个字节都使用 i2c 从设备传输到 PC:现在为了性能,最好只使用
packed
来避免“末尾的额外填充”,或者,它是最好去packed,aligned
每次传输时传输和读取额外未使用的“末尾填充”字节?
aligned
声明上的struct
属性意味着结构体的任何实例都必须从对齐的地址开始。
这也意味着,如果您有一个结构数组,该结构可能需要尾部填充,以便数组的每个成员正确对齐。
虽然
packed
属性将最小化结构中使用的任何填充,但与 aligned
结合使用时,不一定完全消除此类填充。