为什么必须在 typedef 中指定此对齐属性?
Why does this alignment attribute have to be specified in a typedef?
我最初是在我的平板电脑上写这个问题的,并且在这样做时采取了很多捷径,所以我认为最终会导致阅读 and/or 试图回答这个问题的人感到困惑。
我不是在寻求解决我最初遇到的问题的方法。如果您真的想了解背景故事,请阅读下一段,否则请跳过。
导致此问题的原因是一些旧代码对 {struct, data, struct, data, ...}
形式的数据数组进行操作,其中每个 data
具有任意长度。代码通过指针访问每个结构,当我们切换到 gcc 时,由于访问未对齐,它开始在 Solaris 中崩溃。解决这个问题的一个想法是改变类型的对齐方式,如下所示,但我可能不会那样做。
要回答的问题可以概括为:
- 文档指出无法使用
aligned
减少对齐,但我可以使用 typedef 来做到这一点。它是否按预期工作?
- 如果它按预期工作,为什么它需要 typedef?为什么我不能降低对齐作为结构定义的一部分?
- 注意:
typedef struct {...}__attribute__((aligned(1))) Typename;
也可以
这是 link to some sample code running on wandbox。如果 link 死机:
#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;
}
来自 gcc help files
You may specify the aligned and transparent_union attributes either in a typedef declaration or just past the closing curly brace of a complete enum, struct or union type definition and the packed attribute only past the closing brace of a definition.
所以你可以使用
struct Test_t {
int x;
double y;
float z;
} __attribute__((aligned(1)));
然后用
定义变量
struct Test_t a,b;
struct Test_t *test;
或者你可以使用上面给出的方式。是一样的。
我找到了答案。我一定是瞎了。来自 GCC 文档:
When used on a struct, or struct member, the aligned attribute can only increase the alignment; in order to decrease it, the packed attribute must be specified as well. When used as part of a typedef, the aligned attribute can both increase and decrease alignment, and specifying the packed attribute generates a warning.
我最初是在我的平板电脑上写这个问题的,并且在这样做时采取了很多捷径,所以我认为最终会导致阅读 and/or 试图回答这个问题的人感到困惑。
我不是在寻求解决我最初遇到的问题的方法。如果您真的想了解背景故事,请阅读下一段,否则请跳过。
导致此问题的原因是一些旧代码对 {struct, data, struct, data, ...}
形式的数据数组进行操作,其中每个 data
具有任意长度。代码通过指针访问每个结构,当我们切换到 gcc 时,由于访问未对齐,它开始在 Solaris 中崩溃。解决这个问题的一个想法是改变类型的对齐方式,如下所示,但我可能不会那样做。
要回答的问题可以概括为:
- 文档指出无法使用
aligned
减少对齐,但我可以使用 typedef 来做到这一点。它是否按预期工作? - 如果它按预期工作,为什么它需要 typedef?为什么我不能降低对齐作为结构定义的一部分?
- 注意:
typedef struct {...}__attribute__((aligned(1))) Typename;
也可以
- 注意:
这是 link to some sample code running on wandbox。如果 link 死机:
#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;
}
来自 gcc help files
You may specify the aligned and transparent_union attributes either in a typedef declaration or just past the closing curly brace of a complete enum, struct or union type definition and the packed attribute only past the closing brace of a definition.
所以你可以使用
struct Test_t {
int x;
double y;
float z;
} __attribute__((aligned(1)));
然后用
定义变量struct Test_t a,b;
struct Test_t *test;
或者你可以使用上面给出的方式。是一样的。
我找到了答案。我一定是瞎了。来自 GCC 文档:
When used on a struct, or struct member, the aligned attribute can only increase the alignment; in order to decrease it, the packed attribute must be specified as well. When used as part of a typedef, the aligned attribute can both increase and decrease alignment, and specifying the packed attribute generates a warning.