为什么必须在typedef中指定此对齐属性?

时间:2016-12-16 08:21:25

标签: c attributes memory-alignment struct-member-alignment

我最初是从平板电脑上写下这个问题并采取了很多捷径,我认为最终会导致阅读和/或试图回答问题的人感到困惑。

我不是要求解决我最初开始的问题。如果你真的想要后面的故事阅读下一段,否则跳过它。

带来这一点的是一些旧代码,它运行在{struct, data, struct, data, ...}形式的数据数组上,其中每个data具有任意长度。代码通过指针访问每个结构,当我们切换到gcc时,由于访问不对齐,它开始在Solaris中崩溃。解决这个问题的一个想法是改变类型的对齐方式,如下所示,但我可能不会这样做。

要回答的问题可归纳为:

  • 使用aligned无法减少文档状态对齐,但我可以使用typedef进行对齐。它是否按预期工作?
  • 如果它按预期工作,为什么需要typedef?为什么我不能将对齐降低为结构定义的一部分?
    • note :可以使用typedef struct {...}__attribute__((aligned(1))) Typename;
    • 完成

这是一个link to some sample code running on wandbox。如果链接失效:

#include <cstdio>
#include <assert.h>

#define ALIGN __attribute__((aligned(1)))

struct       Misaligned_1_t { int x; double y; float z; };
struct ALIGN Misaligned_2_t { int x; double y; float z; };
struct       Misaligned_3_t { int x; double y; float z; } ALIGN;

// The gcc documentation indicates that the "aligned" attribute
// can only be used to increase alignment, so I was surprised
// to discover this actually works.  Why does it work?
typedef Misaligned_1_t ALIGN Aligned_t;

int main( int, char** ) {
  char buffer[256];
  // The following is meant to simulate a more complicated scenario:
  //   {SomeStruct, char[arbitrary length], SomeStruct, char[arbitrary length], ...}
  // ... where accessing, using and changing each SomeStruct will result in
  // misaligned accesses.
  auto *m1 = (Misaligned_1_t*)&buffer[1];
  auto *m2 = (Misaligned_1_t*)&buffer[1];
  auto *m3 = (Misaligned_1_t*)&buffer[1];
  auto *a1 = (Aligned_t*)&buffer[1];

  // The documentation says we can only reduce alignment with the "packed" attribute,
  // but that would change the size/layout of the structs.  This is to demonstrate
  // that each type is the same size (and should have the same layout).
  assert(   sizeof(m1) == sizeof(m2)
         && sizeof(m1) == sizeof(m3)
         && sizeof(m1) == sizeof(a1) );

  m1->y = 3.14159265358979323846264; // misaligned access

  std::printf( "%0.16f\n", m2->y ); // misaligned access
  std::printf( "%0.16f\n", m3->y ); // misaligned access
  std::printf( "%0.16f\n", a1->y ); // works fine

  return 0;
}

2 个答案:

答案 0 :(得分:2)

来自gcc help files

  

您可以在typedef声明中指定aligned和transparent_union属性,或者只是在完整枚举,结构或联合类型定义的结束大括号之后,并且仅在定义的右大括号之后指定packed属性。

所以你可以使用

struct Test_t {
  int x;
  double y;
  float z;
} __attribute__((aligned(1)));

然后使用

定义变量
struct Test_t a,b;
struct Test_t *test;

或者您可以使用上面给出的方式。它是一样的。

答案 1 :(得分:0)

我找到了答案。我必须失明。来自GCC文件:

  

在结构或结构成员上使用时,aligned属性只能增加对齐;为了减少它,还必须指定packed属性。 当用作typedef的一部分时,aligned属性可以增加和减少对齐,指定packed属性会生成警告。