C struct元素对齐(ansi)

时间:2013-12-20 15:17:49

标签: c++ c standards ansi memory-alignment

只是一个简单的问题......关于结构成员对齐的标准是什么? 例如,这个:

struct
{
    uint8_t a;
    uint8_t b;
    /* other members */
} test;

保证b与struct start的偏移量为1? 感谢

6 个答案:

答案 0 :(得分:7)

标准(截至C99)并没有真正说什么。

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

答案 1 :(得分:1)

C11 6.7.2.1结构和联合说明符 p14表示

  

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

意味着您无法对ab的地址之间的差异做出任何可移植的假设。

答案 2 :(得分:1)

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

对于C,对齐是实现定义的,我们可以看到草案C99标准部分6.7.2.1 结构和联合说明符 12 (在C11中将是第14段,其中说:

  

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

和段 13 说:

  

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

对于 C ++ ,我们在草案标准部分9.2 类成员段落 13 中有以下类似的引号:< / p>

  

分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。具有不同访问控制的非静态数据成员的分配顺序未指定(第11条)。实现对齐要求可能导致两个相邻成员不能立即分配;

和段 19 说:

  

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

答案 3 :(得分:0)

你正在使用的情况并不是一个边缘情况,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;

无论如何,这总是取决于目标架构和编译器......

答案 4 :(得分:0)

第6.4章(第138页)中的K&amp; R第二版(ANSI C)说:

  

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

所以不,ANSI C不保证b在偏移量为1。

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

某些编译器支持pack-pragmas,因此您可以强制struct中没有此类“漏洞”,但这不是可移植的。

答案 5 :(得分:0)

其他答案已经提到了C-Standard所保证的内容。

但是,要确保b 位于偏移1,您的编译器可能会提供“打包”结构的选项,会说要明确添加否< / strong>填充。

对于gcc,这可以通过#pragma pack()来实现。

#pragma pack(1)
struct
{
  uint8_t a; /* Guaranteed to be at offset 0. */
  uint8_t b; /* Guaranteed to be at offset 1. */
  /* other members are guaranteed to start at offset 2. */
} test_packed;
#pragma pack()

struct
{
  uint8_t a; /* Guaranteed to by at offset 0. */
  uint8_t b; /* NOT guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_unpacked;

便携式(和保存)解决方案是简单地使用数组:

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;