2

以下代码;

struct s1 {
    void *a;
    char b[2];
    int c;
};

struct s2 {
    void *a;
    char b[2];
    int c;
}__attribute__((packed));

如果s1大小为 12 字节且s2大小为 10 字节,这是由于数据以 4 字节块读取}__attribute__((packed));并将大小减小void*a;到仅 2 字节吗?

有点困惑是做什么}__attribute__((packed));的。

非常感谢

4

3 回答 3

5

这是由于对齐,编译器在字段之间添加隐藏的“垃圾”以确保它们具有最佳(性能)起始地址的过程。

使用packed会强制编译器不这样做,这通常意味着如果硬件在对不是 4 的倍数的地址进行 32 位访问时遇到问题,访问结构会变得更慢(或者根本不可能,导致例如总线错误)。

于 2013-08-13T11:06:23.350 回答
2

在 Intel 处理器上,32 位对齐数据的获取比未对齐数据快得多;在许多其他处理器上,未对齐的提取可能完全是非法的,或者需要使用 2 条指令进行模拟。因此,第一个结构将c始终在这些 32 位架构上与可被 4 整除的字节地址对齐。然而,这需要在存储中浪费 2 个字节。

struct s1 {
    void *a;
    char b[2];
    int c;
};

// Byte layout in memory (32-bit little-endian):
// | a0 | a1 | a2 | a3 | b0 | b1 | NA | NA | c0 | c1 | c2 | c3 |
// addresses increasing ====>

另一方面,有时您绝对需要将一些未对齐的数据结构(如文件格式或网络数据包)按原样映射到 C 结构中;在那里你可以使用__attribute__((packed))来指定你想要没有填充字节的所有内容:

struct s2 {
    void *a;
    char b[2];
    int c;
} __attribute__((packed));

// Byte layout in memory (32-bit little-endian):
// | a0 | a1 | a2 | a3 | b0 | b1 | c0 | c1 | c2 | c3 |
// addresses increasing ====>
于 2013-08-13T11:19:23.390 回答
0

这是由于数据结构对齐,这是两个过程的组合:数据对齐和数据填充。如您所说,第一个结构将与单词对齐,但是第二个结构已打包并强制编译器不将结构填充到单词中。

第二个结构是 10 个字节,因为字符数组是 2 个字节,而不是void 指针(它仍然是 4 个字节,所有指针都是)。这可能会影响性能,因为 2 字节空间的折衷不值得硬件损失的效率(在大多数情况下),并且可能导致未定义的行为。

于 2013-08-13T11:10:27.543 回答