简体   繁体   English

指定64位对齐

[英]Specifying 64-bit alignment

Given a structure definition like 给定一个结构定义

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

What's the best (simplest, most reliable and portable) way to specify that it should always be aligned to a 64-bit address, even on a 32-bit build? 什么是最好的(最简单,最可靠和最便携)方式来指定它应该始终与64位地址对齐,即使在32位构建上也是如此? I'm using C++11 with GCC 4.5.2, and hoping to also support Clang. 我正在使用C ++ 11和GCC 4.5.2,并希望也支持Clang。

Since you say you're using GCC and hoping to support Clang, GCC's aligned attribute should do the trick: 既然你说你正在使用GCC并希望支持Clang,那么GCC的aligned 属性应该可以解决问题:

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

The following is reasonably portable, in the sense that it will work on a lot of different implementations, but not all: 以下是相当便携的,因为它可以在很多不同的实现上工作,但不是全部:

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

static char assert_foo_size[sizeof(foo) % 8 == 0 ? 1 : -1];

That will fail to compile unless either: 除非有以下情况,否则无法编译:

  • the compiler has added some padding to foo to bring it to a multiple of 8, which normally would only happen for reason of an alignment requirement, or 编译器为foo添加了一些填充,使其达到8的倍数,这通常只是出于对齐要求而发生,或者
  • the layout of foo.data is extremely strange, or foo.data的布局非常奇怪,或者
  • one of long long and double is bigger than 3 ints, and a multiple of 8. Which doesn't necessarily mean it's 8-aligned. long longdouble一个大于3个int,是8的倍数。这并不一定意味着它是8-aligned。

Given that you only need to support 2 compilers though, and clang is fairly gcc-compatible by design, just use the __attribute__ that works. 鉴于您只需要支持2个编译器,并且clang在设计上与gcc兼容,只需使用有效的__attribute__ Only think of doing anything else if you want to write code now that will (hopefully) work on compilers you're not testing on. 如果你现在想要编写代码,那么只考虑做其他任何事情(希望)可以在你没有测试的编译器上工作。

C++11 adds alignof , which you can test instead of testing the size. C ++ 11添加了alignof ,您可以测试而不是测试大小。 It will remove the false positives, but still leave you with some conforming implementations on which the union fails to create the alignment you want, and hence fails to compile. 它将删除误报,但仍然留下一些符合实现的联合无法创建所需的对齐,因此无法编译。 Also, my sizeof trick is quite limited, it doesn't help at all if your structure has 4 ints instead of only 3, whereas the same thing with alignof does. 另外,我的sizeof技巧是非常有限的,如果你的结构有4个整数而不是3个整数,它根本无济于事,而对于alignof则相同。 I don't know what versions of gcc and clang support alignof , which is why I didn't use it to start with. 我不知道什么版本的gcc和clang支持alignof ,这就是我没有用它开始的原因。 I wouldn't have thought it's difficult to do. 我不会想到这很难。

By the way, if instances of foo are dynamically allocated then things get easier. 顺便说一句,如果foo实例是动态分配的,那么事情会变得更容易。 Firstly, I suspect that glibc or similar malloc implementations will 8-align anyway -- if there's a basic type with an 8-byte alignment then malloc has to, and I think glibc malloc just does always, rather than worrying about whether there is or not on any given platform. 首先,我怀疑glibc或类似的malloc实现无论如何都会8对齐 - 如果有一个8字节对齐的基本类型,那么malloc必须这样做,而且我认为glibc malloc总是这样做,而不是担心是否存在或者不在任何给定的平台上。 Secondly, there's posix_memalign to be sure. 其次,有确定的posix_memalign

You should use __attribute__((aligned(8)) . However, I found this description only make sure allocated size of structure is multiple of 8 Bytes. It does not make sure start address is the multiple. 你应该使用__attribute__((aligned(8)) 。但是,我发现这个描述只确保结构的分配大小是8字节的倍数。它不能确保起始地址是多个。

For example. 例如。 I use __attribute__((aligned(64)) , malloc may return a 64Byte-length structure whose start address is 0xed2030. 我使用__attribute__((aligned(64)) ,malloc可能返回一个64Byte-length结构,其起始地址为0xed2030。

If you want start address is aligned, you should use aligned_alloc: gcc aligned allocation . 如果要将起始地址对齐,则应使用aligned_alloc: gcc对齐分配 aligned_alloc(64, sizeof(foo) will return 0xed2040. aligned_alloc(64, sizeof(foo)将返回0xed2040。

Portable? 便携式? I don't really know about a really portable way. 我真的不知道一种非常便携的方式。 GCC has __attribute__((aligned(8))) , and other compilers may also have equivalents, which you can detect using preprocessor directives. GCC具有__attribute__((aligned(8))) ,而其他编译器也可能具有等价物,您可以使用预处理器指令进行检测。

I'm pretty sure gcc 4.5.2 is old enough that it doesn't support the standard version yet, but C++11 adds some types specifically to deal with alignment -- std::aligned_storage and std::aligned_union among other things (see §20.9.7.6 for more details). 我很确定gcc 4.5.2已经足够老了它还不支持标准版本,但C ++ 11增加了一些专门用于处理对齐的类型 - std::aligned_storagestd::aligned_union等等(更多细节见§20.9.7.6)。

Seems to me that the most obvious way to do this would be to use Boost's implementation of aligned_storage (or TR1's, if you have that). 在我看来,最明显的方法是使用Boost实现的aligned_storage (或TR1,如果你有的话)。 If you don't want that, I'd still think hard about using the standard version in most of your code, and just write a small implementation of it for your own use until you update to a compiler that implements the standard. 如果您不想这样,我仍然会在大多数代码中使用标准版本,并且只需编写一个小的实现供您自己使用,直到您更新到实现该标准的编译器。 Portable code, however, will still look slightly different from most that uses something like __declspec(align... or __attribute__(__aligned__, ... directly. 但是,可移植代码仍然会与大多数使用类似__declspec(align...__attribute__(__aligned__, ...略有不同。

In particular, it just gives you a raw buffer of a requested size with a requested alignment. 特别是,它只是为您提供了一个请求对齐的请求大小的原始缓冲区。 it's then up to you to use something like placement new to create an object of your type in that storage. 然后由你来使用像placement new这样的东西在你的存储中创建你的类型的对象。

For what it's worth, here's a quick stab at an implementation of aligned_storage based on gcc's __attribute__(__aligned__,... directive: 对于它的价值,这里是基于gcc的__attribute__(__aligned__,...指令)快速实现aligned_storage的实现:

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

A quick test program to show how to use this: 一个快速测试程序,展示如何使用它:

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

Of course, in real use you'd wrap up/hide most of the ugliness I've shown here. 当然,在实际使用中,你可以收拾/隐藏我在这里展示的大部分丑陋。 If you leave it like this, the price of (theoretical/future) portability is probably excessive. 如果你这样离开,(理论/未来)便携性的价格可能过高。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM