内存对齐:如何使用alignof / alignas?

时间:2013-06-13 15:44:04

标签: c++ c++11 x86-64 memory-alignment

我现在正在使用共享内存。

我无法理解alignofalignas

cppreference不清楚:alignof返回“对齐”,但什么是“对齐”?要为要对齐的下一个块添加的字节数?填充尺寸? Stack overflow /博客条目也不清楚。

有人可以清楚解释alignofalignas吗?

4 个答案:

答案 0 :(得分:61)

对齐是对存储器位置的限制,可以存储值的第一个字节。 (需要提高处理器的性能并允许使用某些仅适用于具有特定对齐的数据的指令,例如SSE需要对齐到16个字节,而AVX需要对齐到32个字节。)

16的对齐意味着16的倍数的存储器地址是唯一有效的地址。

alignas

强制对齐到所需的字节数(cppreference没有提到它,但我认为你只能对齐2:1,2,4,8,16,32,64,128 ......的幂) / p>

#include <cstdlib>
#include <iostream>

int main() {
    alignas(16) int a[4];
    alignas(1024) int b[4];
    printf("%p\n", a);
    printf("%p", b);
}

示例输出:

0xbfa493e0
0xbfa49000  // note how many more "zeros" now.
// binary equivalent
1011 1111 1010 0100 1001 0011 1110 0000
1011 1111 1010 0100 1001 0000 0000 0000 // every zero is just a extra power of 2

其他关键字

alignof

非常方便,你不能做像

这样的事情
int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error

但你可以做到

assert(alignof(a) == 16);
assert(alignof(b) == 1024);

请注意,实际上这比简单的“%”(模数)操作更严格。事实上,我们知道对齐到1024字节的东西必须与1,2,4,8字节对齐,但

 assert(alignof(b) == 32); // fail.

更确切地说,“alignof”会返回2的最大幂,以便对齐。

另外,alignof是一种很好的方法,可以事先知道基本数据类型的最小对齐要求(对于字符,它可能会返回1,对于浮点数,它可能会返回4)。

仍然合法:

alignas(alignof(float)) float SqDistance;

对齐为16的东西将被放置在下一个16的倍数的可用地址(可能存在来自上次使用地址的隐式填充)。

答案 1 :(得分:6)

对齐不是填充(尽管有时会引入填充以满足对齐要求)。它是C ++类型的内在属性。把它放在标准(3.11[basic.align]

  

对象类型具有对齐要求(3.9.1,3.9.2),这些要求对可以分配该类型的对象的地址施加限制。对齐是实现定义的整数值,表示可以分配给定对象的连续地址之间的字节数。对象类型对该类型的每个对象强制对齐要求;可以使用对齐说明符(7.6.2)请求更严格的对齐。

答案 2 :(得分:4)

每种类型都有对齐要求。通常,这样可以有效地访问类型的变量,而不必使CPU生成多个读/写访问权限以便到达数据类型的任何给定成员。此外,它还确保有效复制整个变量。 alignof将返回给定类型的对齐要求。

alignas用于强制对数据类型进行对齐(只要它不低于alignof所述数据类型将返回的严格程度)

答案 3 :(得分:3)

对齐方式是与内存地址相关的属性。简单地说,如果地址X与Z对齐,则x是Z的倍数,即X = Zn + 0。这里重要的是Z总是2的幂。

对齐是内存地址的属性,表示为以2的幂为模的数字地址。对于 例如,地址0x0001103F模4为3。该地址被称为与4n + 3对齐,其中4表示 选择的2的幂。地址的对齐方式取决于选择的2的幂。相同的地址模8为7。如果地址的对齐方式为Xn + 0,则称地址与X对齐。

以上声明可在Microsoft c ++参考上找到。

如果某个数据项的地址与大小对齐,则该数据项被称为 自然对齐 ,否则未对齐。 例如:如果将一个大小为4个字节的整数变量存储在一个对齐4的地址中,那么我们可以说该变量是自然对齐的,即该变量的地址应为4的倍数。

编译器始终尝试避免未对齐。对于简单的数据类型,选择地址时应使其是变量大小(以字节为单位)的倍数。在结构自然对齐和访问的情况下,编译器也应适当填充。此处结构将与结构中不同数据项的最大大小对齐。例如:

    struct abc
   {
        int a;
        char b;
   };

结构abc对齐为4 ,这是int成员的大小,显然大于1个字节(char成员的大小)。

alignas

此说明符用于将用户定义的类型(如结构,类等)与2的幂的特定值对齐。

alignof

这是一种运算符,用于获取与结构或类类型对齐的值。 例如:

#include <iostream>
struct alignas(16) Bar
{
    int i; // 4 bytes
    int n; // 4 bytes
    short s; // 2 bytes
};
int main()
{
    std::cout << alignof(Bar) << std::endl; // output: 16
}