【问题标题】:Struct Padding in 32 Bit System32 位系统中的结构填充
【发布时间】:2018-12-24 21:08:05
【问题描述】:

如果有C这样的结构

struct abc
{
uint16_t                    port_no; //2 Bytes
uint8_t                     src_mac[6]; //6 Bytes
}

编译器如何应用填充来对齐 32 位系统上的 4 字节字:

会不会

2 Bytes
Pad[2]
6 Bytes
Pad[2]

2 Byte
6 Byte

【问题讨论】:

  • 对于您的特定编译器(及其版本),您可以使用offsetof 来查找。请注意,它是高度特定于实现的。
  • 很多时候编译器都有结构打包机制
  • 即使对于给定的编译器(版本),结果通常也是特定于目标的。
  • 还可以使用sizeof 检查最后一个成员之后的填充。
  • @Someprogrammerdude 这不是特定于实现的。对齐和填充是架构调用约定的一部分,如果你愿意的话,它是 C 目标文件的 ABI。如果没有通用规则,来自不同编译器的目标文件就无法链接在一起。尽管如此,仍然有很多 32 位系统可供选择。

标签: c struct padding


【解决方案1】:

默认情况下填充是打开的。它会自动在您的结构中插入“间隙”。结果好像有第四个中间变量,像这样:

struct abc
{
    uint16_t  port_no;    // 2 Bytes
    char pad_0[2];        // 2 Bytes
    uint8_t   src_mac[6]; // 6 Bytes
    char pad_1[2];        // 2 Bytes
}

【讨论】:

  • 为什么是char pad_0[2]uint8_t 没有任何对齐先决条件。
  • 编译器增加 2 个字节来填充 32 位。如果需要,您也可以将其视为 uint16_t 而不是 2 个字符,但最后它是相同的...2 个字节
  • ideone.com/Ywr2XP 最常见的架构师之一(linux 64 位 + gcc)不插入填充。
  • 不知道编译器是否会重新排序结构成员来优化
【解决方案2】:

这取决于系统的架构。

在 32 位 MIPS 上,您的结构将没有 任何填充,因为 uint16_t 必须对齐 甚至地址和uint8_t 根本不需要对齐。

但是,struct abc 类型的变量将在 甚至地址,从而最终迫使填充之外 struct(例如,当struct abc 是周围结构的成员时)。

【讨论】:

  • 在 ideone 上是一样的 :-) ideone.com/Ywr2XP Linux 64 bits+gcc
  • 结构的大小为 8(在大多数系统上),因此结构外也没有填充。
【解决方案3】:

在 C/C++ 中,每种类型都有大小和对齐方式,这可能因架构、内核甚至 C/C++ ABI 的不同而不同。

Gcc 提供了一个函数__alignof__,C++11 官方有一个alignof(type-id) 函数,可用于打印类型的对齐要求。普通 C 似乎没有,但每种类型仍然具有该属性。

在内存中,每种类型都必须至少与对齐要求对齐,编译器会将填充插入到确保这种情况的结构中。然后,整个结构具有其任何成员所需的最大对齐方式,并且大小包括填充到结构对齐方式的倍数。

通常,uint16_t 有 2 字节对齐要求,而 chars 有 1 字节对齐要求。所以这个结构有一个 2 字节的对齐要求,根本不需要填充。给结构体的总大小为 8 字节。

但请注意,出于某种原因,架构的调用约定可能需要更多的对齐或填充。

【讨论】:

    猜你喜欢
    • 2014-09-21
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2015-07-23
    相关资源
    最近更新 更多