指定64位对齐

问题描述 投票:12回答:6

给定一个结构定义

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

什么是最好的(最简单,最可靠和最便携)方式来指定它应该始终与64位地址对齐,即使在32位构建上也是如此?我正在使用C ++ 11和GCC 4.5.2,并希望也支持Clang。

c++ gcc alignment
6个回答
15
投票

既然你说你正在使用GCC并希望支持Clang,GCC的aligned attribute就应该这样做:

struct foo {
    int a, b, c;
} __attribute__((__aligned__(8))); // aligned to 8-byte (64-bit) boundary

7
投票

以下是相当便携的,因为它可以在很多不同的实现上工作,但不是全部:

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 longdouble中的一个大于3个整数,是8的倍数。这并不一定意味着它是8对齐的。

鉴于您只需要支持2个编译器,并且clang在设计上与gcc兼容,只需使用有效的__attribute__即可。如果你现在想要编写代码,那么只考虑做其他任何事情(希望)可以在你没有测试的编译器上工作。

C ++ 11添加了alignof,您可以测试而不是测试大小。它将删除误报,但仍然留下一些符合实现的联合无法创建所需的对齐,因此无法编译。此外,我的sizeof技巧是非常有限的,如果你的结构有4个整数而不是3个整数,它根本没有帮助,而与alignof相同的东西。我不知道什么版本的gcc和clang支持alignof,这就是为什么我没有用它开始。我不会想到这很难。

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


4
投票

你应该使用__attribute__((aligned(8))。但是,我发现此描述只确保分配的结构大小是8字节的倍数。它不能确保起始地址是多重的。

例如。我使用__attribute__((aligned(64)),malloc可能会返回64Byte长度的结构,其起始地址为0xed2030。

如果你想要开始地址对齐,你应该使用aligned_alloc:gcc aligned allocationaligned_alloc(64, sizeof(foo)将返回0xed2040。


2
投票

便携式?我真的不知道一种非常便携的方式。 GCC有__attribute__((aligned(8))),其他编译器也可能有等价物,您可以使用预处理器指令检测它们。


1
投票

我很确定gcc 4.5.2已经足够大了它还不支持标准版本,但C ++ 11增加了一些专门用于处理对齐的类型 - std::aligned_storagestd::aligned_union等(参见§20.9.7.6)更多细节)。

在我看来,最明显的方法是使用Boost实现的aligned_storage(或TR1,如果你有的话)。如果您不想这样,我仍然会在大多数代码中使用标准版本,并且只需编写一个小的实现供您自己使用,直到您更新到实现该标准的编译器。然而,便携式代码仍然与大多数使用__declspec(align...__attribute__(__aligned__, ...之类的东西略有不同。

特别是,它只是为您提供了一个请求对齐的请求大小的原始缓冲区。然后由你来使用像placement new这样的东西在你的存储中创建你的类型的对象。

对于它的价值,这里是基于gcc的aligned_storage指令快速刺激__attribute__(__aligned__,...的实现:

template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
    typedef struct {
        __attribute__(__aligned__(Alignment)) unsigned char __data[Len];
    } type;
};

一个快速测试程序,展示如何使用它:

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;
}

当然,在实际使用中,你可以收拾/隐藏我在这里展示的大部分丑陋。如果你这样离开,(理论/未来)便携性的价格可能过高。


1
投票

[[gnu::aligned(64)]] in c++11 annotation std::atomic <int64_t> ob [[gnu::aligned(64)]]

© www.soinside.com 2019 - 2024. All rights reserved.