C++ 指定64位对齐

C++ 指定64位对齐,c++,gcc,alignment,C++,Gcc,Alignment,给定一个结构定义,如 struct foo { int a, b, c; }; 最好的(最简单、最可靠和可移植的)方法是什么来指定它应该始终与64位地址对齐,即使在32位构建上也是如此?我在GCC4.5.2中使用C++11,希望也支持Clang。可移植?我真的不知道什么是真正的便携方式。GCC有\uuuu属性((aligned(8)),其他编译器也可能有等价物,可以使用预处理器指令进行检测。既然您说您正在使用GCC并希望支持Clang,那么GCC的aligned应该可以做到以下几点:

给定一个结构定义,如

struct foo {
    int a, b, c;
};

最好的(最简单、最可靠和可移植的)方法是什么来指定它应该始终与64位地址对齐,即使在32位构建上也是如此?我在GCC4.5.2中使用C++11,希望也支持Clang。

可移植?我真的不知道什么是真正的便携方式。GCC有
\uuuu属性((aligned(8))
,其他编译器也可能有等价物,可以使用预处理器指令进行检测。

既然您说您正在使用GCC并希望支持Clang,那么GCC的
aligned
应该可以做到以下几点:

struct foo {
    int a, b, c;
} __attribute__((__aligned__(8))); // aligned to 8-byte (64-bit) boundary
以下是合理的可移植性,因为它可以在许多不同的实现上工作,但不是所有实现上都可以:

union foo {
    struct {int a, b, c; } data;
    double padding1;
    long long padding2;
};

static char assert_foo_size[sizeof(foo) % 8 == 0 ? 1 : -1];
将无法编译,除非:

  • 编译器在
    foo
    中添加了一些填充,使其达到8的倍数,这通常只会因为对齐要求而发生,或者
  • foo.data
    的布局非常奇怪,或者
  • long-long
    double
    中的一个大于3整数,是8的倍数。这并不一定意味着它是8对齐的
考虑到您只需要支持2个编译器,并且clang在设计上与gcc相当兼容,只需使用有效的
\uuuu属性
。如果您现在想编写能够(希望)在您没有测试的编译器上工作的代码,那么只考虑做其他事情

C++11添加了
alignof
,您可以测试它,而不是测试大小。它将消除误报,但仍然会给您留下一些一致性的实现,其中union无法创建您想要的对齐方式,因此无法编译。另外,我的
sizeof
技巧非常有限,如果您的结构只有4个int而不是3个int,那么它根本没有帮助,而
alignof
的方法也是如此。我不知道什么版本的gcc和clang支持
alignof
,这就是为什么我一开始没有使用它的原因。我不认为这很难做到


顺便说一下,如果动态分配
foo
的实例,那么事情就会变得更容易。首先,我怀疑glibc或类似的
malloc
实现无论如何都会采用8字节对齐方式——如果有一个基本类型采用8字节对齐方式,那么
malloc
必须这样做,我认为glibc
malloc
总是这样,而不是担心在任何给定的平台上是否存在。其次,可以肯定的是,posix_memalign有

我很确定gcc 4.5.2已经足够老了,它还不支持标准版本,但C++11添加了一些专门处理对齐的类型--
std::aligned_storage
std::aligned_union
(有关详细信息,请参见§20.9.7.6)

在我看来,实现这一点最明显的方法是使用Boost的
aligned_storage
(或者TR1,如果有的话)。如果您不想这样做,我仍然会认真考虑在大多数代码中使用标准版本,只需编写一个供您自己使用的小型实现,直到您更新到实现该标准的编译器。然而,可移植代码与大多数直接使用
\uuu declspec(align…
\uuu attribute(aligned…
\uuu属性)的代码看起来仍然略有不同

特别是,它只给你一个原始缓冲区,它的大小和对齐方式都是要求的,然后你就可以使用placement new之类的东西在该存储中创建一个你喜欢的对象了

值得一提的是,这里有一个基于gcc的
\uuuuuu属性(\uuuuu aligned\uuuu,…
指令的
对齐存储的快速实现:

template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
    typedef struct {
        __attribute__(__aligned__(Alignment)) unsigned char __data[Len];
    } type;
};
模板
结构对齐存储{
类型定义结构{
__属性(对齐)无符号字符数据[Len];
}类型;
};
演示如何使用此功能的快速测试程序:

struct foo {
    int a, b, c;

    void *operator new(size_t, void *in) { return in; }
};

int main() {
    stdx::aligned_storage<sizeof(foo), 8>::type buf;

    foo& f = *new (static_cast<void*>(&buf)) foo();

    int address = *reinterpret_cast<int *>(&f);

    if (address & 0x3 != 0)
        std::cout << "Failed.\n";

    f.~foo();

    return 0;
}
structfoo{
INTA、b、c;
void*运算符new(size_t,void*in){return in;}
};
int main(){
stdx::aligned_storage::type buf;
foo&f=*new(static_cast(&buf))foo();
int address=*重新解释强制转换(&f);
如果(地址&0x3!=0)

std::cout您应该使用
\uuuu属性((对齐(8))
。但是,我发现此描述仅确保结构的分配大小是8字节的倍数。它不确保起始地址是倍数

例如,我使用
\uuuuu属性((对齐(64))
,malloc可能返回一个64字节长的结构,其起始地址为0xed2030

如果希望起始地址对齐,则应使用对齐的\u alloc: .alloc(64,sizeof(foo)
将返回0xed2040。


c++11注释中的[gnu::aligned(64)]
标准::原子对象[[gnu::对齐(64)]]

我很好奇;为什么32位系统上的对齐方式很重要?或者,实际上,在64位系统上,因为该结构通常不需要超过32位对齐。一旦编译器支持它,您就可以使用alignas。@JonathanLefler:我假设允许某些自动sse优化。gcc最近添加了d一些内置的假定是对齐的,以告诉编译器应该对齐内容。使用示例可能会提供更多的见解。@Plasmah:是的,但是GCC 4.5.2(甚至不是4.7.0)不需要。而且您必须将64位对齐类型传递给
alignas
。那么您将传递哪种类型?因为我计划使用指针的低阶位作为标记位。典型的用例是64位平台和指针密集型数据结构,给我三个标记位,但我想确保在编译32位时代码仍然有效是不可移植的。但是那样的话,什么都不会。@johndilling:我知道。它可以移植到正在讨论的两个编译器。根据你链接的文档,这不应该是uuu属性uu((对齐(8))吗?@D0SBoots:第二个p