结构中成员的错位

时间:2014-05-14 20:10:53

标签: c structure bit-fields

在C中,有时结构的某些成员倾向于具有未对齐的偏移量,如HPUX community中的此线程

在这种情况下,建议使用零宽度位字段来对齐(未对齐的)下一个成员。 在什么情况下结构成员的错位发生?在字边界处对齐成员偏移不是编译器的工作吗?

2 个答案:

答案 0 :(得分:4)

只有在故意隐藏结构构件的对准要求时,才会出现结构构件的“未对准”。 (或者,如果使用某些特定于实现的机制来抑制对齐,例如gcc的packed属性`。)

例如,在引用的问题中,问题是存在结构:

struct {
    // ... stuff
    int               val;
    unsigned char     data[DATA_SIZE];
    // ... more stuff
}

并且程序员尝试使用data,就好像它是size_t

*(size_t*)s->data

但是,程序员已将data声明为unsigned char,因此编译器仅保证将其对齐以用作unsigned char

碰巧,data跟在int之后,因此也会与int对齐。在某些体系结构上,这可行,但在目标体系结构上,size_t大于int并且需要更严格的对齐。

显然,编译器无法知道您打算使用结构成员,就像它是其他类型一样。如果你这样做并编译一个需要正确对齐的架构,你可能会遇到问题。

引用的线程建议在声明size_t数组之前插入一个零长度unsigned char位字段,以强制数组与size_t对齐。虽然该解决方案可能适用于目标体系结构,但它不可移植,不应在便携式代码中使用。不能保证0长度的比特字段将占用0比特,也不能保证基于size_t的比特字段实际存储在size_t中或者被适当地对齐任何非比特字段使用。

更好的解决方案是使用匿名联盟:

// ...
int             val;
union {
  size_t        dummy;
  unsigned char data[DATA_SIZE];
};
// ...

使用C11,您可以明确指定最小对齐:

// ...
int                            val;
_Alignas(size_t) unsigned char data[DATA_SIZE];
// ...

在这种情况下,如果你#include <stdalign.h>,你可以用一种也适用于C ++ 11的方式拼写_Alignas

int                            val;
alignas(size_t) unsigned char data[DATA_SIZE];

答案 1 :(得分:1)

问:为什么会发生错位?在字边界处对齐成员偏移不是编译器的工作吗?

您可能已经意识到结构字段与特定边界对齐的原因是为了提高性能。正确对齐的字段可能仅需要CPU的单个存储器提取操作;错误对齐的字段需要至少两次内存提取操作(CPU时间的两倍)。

正如您所指出的,编译器工作是将结构字段对齐以获得最快的CPU访问;除非程序员超越编译器的默认行为。

然后问题可能是;为什么程序员会忽略编译器结构字段的默认对齐?

程序员想要覆盖默认路线的原因的一个例子是在线路上发送一个结构&#39;到另一台电脑。通常,程序员希望将尽可能多的数据打包到最少的字节数。

因此,当结构密度比访问结构字段的CPU性能更重要时,程序员将禁用默认对齐。