14

给定一个结构定义,如

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

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

4

6 回答 6

16

既然您说您正在使用 GCC 并希望支持 Clang,那么 GCC 的aligned 属性应该可以解决问题:

struct foo {
    int a, b, c;
} __attribute__((__aligned__(8))); // aligned to 8-byte (64-bit) boundary
于 2012-06-08T14:46:52.980 回答
8

以下是相当可移植的,因为它将适用于许多不同的实现,但不是全部:

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我认为 glibcmalloc总是这样做,而不是担心是否有任何给定平台。其次,posix_memalign要确定。

于 2012-06-08T15:20:01.223 回答
5

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

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

如果要对齐起始地址,则应使用对齐的alloc: gcc对齐分配aligned_alloc(64, sizeof(foo)将返回 0xed2040。

于 2016-07-08T06:31:39.477 回答
2

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

于 2012-06-08T14:46:23.553 回答
2

我很确定 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之类的东西在该存储中创建您类型的对象。

对于它的价值,这里有一个aligned_storage基于 gcc__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;
}

当然,在实际使用中,您会包装/隐藏我在这里展示的大部分丑陋。如果你这样离开它,(理论/未来)可移植性的价格可能过高。

于 2012-06-08T15:39:17.460 回答
1

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

于 2018-09-06T03:44:21.557 回答