C++ C结构元素对齐(ansi)

C++ C结构元素对齐(ansi),c++,c,standards,ansi,memory-alignment,C++,C,Standards,Ansi,Memory Alignment,只是一个简单的问题。。。标准对结构构件对齐有何规定? 举个例子: struct { uint8_t a; uint8_t b; /* other members */ } test; 保证b位于结构起点的偏移量1处? 谢谢标准(从C99开始)没有真正说明什么 唯一真正的保证是(void*)和test==(void*)和a,并且a的地址低于b。其他一切都取决于实现。C116.7.2.1结构和联合说明符p14 结构或联合对象的每个非位字段成员在中对齐 适合其类型的实现定义的

只是一个简单的问题。。。标准对结构构件对齐有何规定? 举个例子:

struct
{
    uint8_t a;
    uint8_t b;
    /* other members */
} test;
保证b位于结构起点的偏移量1处? 谢谢

标准(从C99开始)没有真正说明什么

唯一真正的保证是
(void*)和test==(void*)和a
,并且
a
的地址低于
b
。其他一切都取决于实现。

C116.7.2.1结构和联合说明符p14

结构或联合对象的每个非位字段成员在中对齐 适合其类型的实现定义的方式


这意味着您不能对
a
b
的地址之间的差异做出任何可移植的假设。您使用的大小写并不是真正的边缘大小写,两个uint_8都足够小,可以放入内存中的同一个字,并且将每个uint_8放入uint_16中是没有用的

更关键的情况是:

{
    uint8_t a;
    uint8_t b;

    uint_32 c; // where is C, at &a+2 or &a+4 ?
    /* other members */
} test;

无论如何,这将始终取决于目标体系结构和编译器…

应该可以使用它来确定成员的偏移量

对于C,校准是实施定义的,我们可以在C99标准草案第6.7.2.1节《结构和联合规范》第12段(在C11中为第14段)中看到,其中规定:

结构或联合对象的每个非位字段成员以适合其类型的实现定义的方式对齐

第13段说:

在结构对象中,非位字段成员和位字段所在的单位 驻存地址按声明顺序增加。指向 经过适当转换的结构对象指向其初始成员(或者如果该成员是 位字段,然后发送到它所在的单元),反之亦然。可能有未命名的 在结构对象内填充,但不在其开头填充

对于C++,我们有以下相似的引用标准草案部分:代码>9.2 <代码>类成员13段落表示:

具有相同访问控制(第11条)的(非联合)类的非静态数据成员被分配,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序(第11条)。实施一致性要求可能会导致两个相邻的成员不能紧随其后进行分配

第19段说:

指向标准布局结构对象的指针(使用reinterpret_转换进行适当转换)指向其 初始成员(或者如果该成员是位字段,则指向其所在的单元),反之亦然。[注: 因此,在标准布局结构对象中可能存在未命名的填充,但在其开头不存在, 如有必要,以实现适当对齐。-结束注释]

K&R第二版(ANSI C)第6.4章(第138页)规定:

但是,不要假设结构的大小是其成员大小的总和。由于不同对象的对齐要求,结构中可能存在未命名的“孔”

因此,不,ANSI C不保证
b
在偏移量1处

编译器甚至可能将
b
放在偏移量
sizeof(int)
处,以便它与机器字的大小对齐,这更容易处理


一些编译器支持,因此您可以强制在
结构中不存在这样的“漏洞”,但这是不可移植的。

其他答案已经提到了C标准所保证的内容

但是,为了确保
b
位于偏移量
1
处,编译器可能会提供“打包”结构的选项,会说显式添加填充

对于gcc,这可以通过以下方式实现


一个可移植(并可保存)的解决方案是简单地使用阵列:

struct
{
  uint8_t ab[2]; /* ab[0] is guaranteed to be at offset 0. */
                 /* ab[1] is guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_packed;

许多编译器都有相当方便的库宏。C11有对齐,ANSI C没有。第一个保证是不需要说明的:
A
位于偏移量
0
。我后来在回答中添加了这个,不确定我是如何忘记它的,但可能会有帮助。是的,但是
\pragma pack
不一定安全;请看@KeithThompson:这是正确的。所以我建议采用基于阵列的解决方案。
struct
{
  uint8_t ab[2]; /* ab[0] is guaranteed to be at offset 0. */
                 /* ab[1] is guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_packed;