C(++)struct强制额外填充

zeb*_*h49 9 c c++ gcc struct memory-alignment

我已经看到了无数问题的形式"我不喜欢填充如何关闭它",但还没有找到任何关于强制编译器提供额外填充的内容.

我的具体情况看起来像

struct particle{
  vect2 s;
  vect2 v;
  int rX;
  int rY;
  double mass;
  int boxNum;
};
Run Code Online (Sandbox Code Playgroud)

哪里vect2很简单struct {double x; double y;} vect2.为了使用SSE2,我需要能够加载一对双精度数,对齐到16字节边界.这曾经工作,直到我添加额外的int,将我的结构大小从48字节推到56字节.结果是段错误.

是否有某种编译器指令我可以使用"填充此结构使其成为16字节长的倍数",或"此结构具有16字节的对齐"?我知道我可以手动完成(例如,添加一个额外的字符[12]),但我真的只是告诉编译器(GCC,最好是ICC兼容),如果我改变它,就不必手动完成结构在未来.

Mar*_*som 8

您可以嵌套两个结构来自动填充它,而无需自己跟踪大小.

struct particle
{
    // ...
};

{
    particle p;
    char padding[16-(sizeof(particle)%16)];
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果结构已经是16的倍数,那么这个版本增加了16个字节.这是不可避免的,因为标准不允许零长度的数组.

有些编译器允许零长度数组作为扩展,在这种情况下,您可以这样做:

struct particle_wrapper
{
    particle p;
    char padding[sizeof(particle)%16 ? 16-(sizeof(particle)%16) : 0];
};
Run Code Online (Sandbox Code Playgroud)

如果结构已经是16的倍数,则此版本不会添加任何填充字节.


Ped*_*dro 5

gcc,您可以使用对齐任意类型和变量__attribute__((aligned(...))).对于你的例子,这将是

struct particle{
  vect2 s;
  vect2 v;
  int rX;
  int rY;
  double mass;
  int boxNum;
} __attribute__((aligned (16)));
Run Code Online (Sandbox Code Playgroud)

这会自动填充结构,以便正确对齐其数组.


zeb*_*h49 3

我正在添加我自己的答案,以防有人来寻找解决方案。马克的解决方案是一个简洁的解决方案,并且满足自动要求,但它不是我最终采用的。我想避免这种情况,这就是我问这个问题的原因,但有一个“微不足道”的解决方案:

struct particle{
  vect2 s;
  vect2 v;
  int rX;
  int rY;
  double mass;
  int boxNum;
  char padding[12];
};
Run Code Online (Sandbox Code Playgroud)

通过手动检查 的当前大小struct,您可以添加适当数量的字符(或其他任何内容,但char可以让您以字节为单位执行此操作),以使其大小正确。这显示了最佳性能以及简单性,尽管它确实需要在每次结构更改时进行更新。在这种情况下,这很好,但如果您有一个可以根据选项更改大小的结构,那就会出现问题。

请注意,我的struct大小是 56 个字节,我添加了 12 个字节使其成为 64 个字节。这个数学运算不起作用,因为尾部int已经被填充了 4 个字节到 8 字节边界;struct之前实际上只有 52 字节。只添加 5char秒就可以了,通过使struct57 个字节长,这将被填充到 64,但这不是一个很好的解决方案,这就是为什么我使用 12 来使它准确地工作。

  • 考虑到性能要求,这似乎是明智的;为了你的同事和未来的维护者(包括你未来的自己),*请*评论修复并添加一个编译时断言,表明“struct”的大小是 16 字节的倍数。 (6认同)
  • 您是否有任何特殊原因不想将其留给编译器,例如使用“__attribute__((aligned(16)))”? (2认同)