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


81

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

我无法理解alignofalignas

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

有人能解释清楚alignofalignas


1
cppreference试图成为参考而非教程
Cubbi 2013年

1
@Cubbi:您也可以在cplusplus.com上查看,有争论的站点更好,对于某些主题cplusplus更好,对于其他cppreference更好,我发现这两个站点在某些时候都不是第一次
CoffeDeveloper 2014年

2
@DarioOO我只是在回答为什么cppreference不能解释alignof页面对齐的概念(现在,在进行中的对象页面上)。我看不到cplusplus.com的相关性。
Cubbi 2014年

Answers:


81

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

对齐16表示唯一的有效地址是16的倍数的内存地址。

alignas

强制对齐到所需的字节数。您只能对齐2、1、2、4、8、16、32、64、128,...的幂

#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是一种提前了解基本数据类型的最小对齐要求的好方法(对于char,它可能会返回1,对于float等会返回4)。

仍然合法:

alignas(alignof(float)) float SqDistance;

然后将对齐方式为16的内容放置在下一个可用地址上,该地址是16的倍数(上次使用的地址可能存在隐式填充)。


10
不同于sizeofalignof只能应用于type-id
neverhoodboy 2014年

alignof()(与对方alignas())在编译时评估,因此没有运行时开销?
不动声色

没有。这是不可能的,编译器在极少数情况下可能会将其作为优化,但通常在评估这两个函数之前,它不知道内存地址如何对齐。只需看看我的示例生成的程序集:goo.gl/ZbemBF
CoffeDeveloper 2014年

1
@Serthy要澄清的alignof 一个编译时常量。alignas不是,并且必须由您的实现new(对标准的要求)或自定义std分配器的支持
Aidiakapi

好的答案,但需要处理struct的结构和成员staticalignas事实证明,它比更加挑剔__attribute__((aligned)),尤其是在像Clang这样的编译器下。
jww

11

对齐方式不是填充(尽管有时会引入填充来满足对齐要求)。它是C ++类型的固有属性。换成标准的(3.11[basic.align]

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


1
很有意思。您介意给出一些例子吗?alignof(struct X)== sizeof(struct X)吗?为什么不 ?
Offirmo

1
@Offirmo否,除非struct X { char a; char b}有把握:在健全的系统上,大小为2,对齐要求为1(可以在任何地址分配,因为可以在任何地址分配char)
Cubbi 2013年

对齐要求1 ???? 哦,我明白了:我认为对齐始终在“自然的” 32位/ 64位边界上,但显然不是。这就解释了事情...因此,在普通计算机上,alignof()结果将始终最大为4(32位)或8(64位),对吗?
Offirmo

@Offirmo“ natural” alignof将在Linux上最大使用alignof(std::max_align_t),这16与我的Linux上的版本无关(无论是否编译-m32或-m64),但是您可以使用alignas
Cubbi

7

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

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


3

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

对齐是内存地址的属性,表示为以2的幂为模的数字地址。例如,地址0x0001103F以4的幂为模。该地址被称为与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的幂的特定值对齐。

对齐

这是一种获取结构或类类型所对应的值的运算符。例如:

#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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.