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

Off*_*rmo 60 c++ x86-64 memory-alignment c++11

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

我无法理解alignofalignas.

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

有人能解释清楚alignofalignas

Gam*_*per 65

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

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

alignas
Run Code Online (Sandbox Code Playgroud)

强制对齐到所需的字节数(cppreference没有提到它,但我认为你只能对齐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);
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

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
Run Code Online (Sandbox Code Playgroud)

另一个关键字

alignof
Run Code Online (Sandbox Code Playgroud)

很方便,你做不了什么

int a[4];
assert(a % 16 == 0); // check if alignment is to 16 bytes: WRONG compiler error
Run Code Online (Sandbox Code Playgroud)

但你可以做到

assert(alignof(a) == 16);
assert(alignof(b) == 1024);
Run Code Online (Sandbox Code Playgroud)

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

 assert(alignof(b) == 32); // fail.
Run Code Online (Sandbox Code Playgroud)

因此更准确地说,"alignof"返回2的最大功率,以便对齐某些东西.

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

仍然合法:

alignas(alignof(float)) float SqDistance;
Run Code Online (Sandbox Code Playgroud)

然后将具有16的对齐的东西放置在下一个可用地址上,该地址是16的倍数(可能存在来自上次使用的地址的隐式填充).

  • 与`sizeof`不同,`alignof`只能应用于`type-id`. (8认同)
  • 很好的答案,但它需要对“结构”和结构中的“静态”成员进行处理。事实证明,“alignas”比“__attribute__((aligned))”更加挑剔,尤其是在像 Clang 这样的编译器下。 (2认同)

JOS*_*NOY 8

对齐是与内存地址相关的属性。简单地说,如果地址 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;
   };
Run Code Online (Sandbox Code Playgroud)

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

利格纳斯

该说明符用于将用户定义的类型(如结构、类等)与特定值(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
}
Run Code Online (Sandbox Code Playgroud)


Cub*_*bbi 7

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

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

  • @Offirmo 不,除非有把握:`struct X { char a; char b}` 的大小为 2,对齐要求为 1,在健全的系统上(它可以分配在任何地址,因为一个 char 可以分配在任何地址) (2认同)

lev*_*gli 7

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

alignas用于强制对数据类型进行对齐(只要alignof所述数据类型返回的内容不那么严格)


110*_*16c 7

要理解alignas并且alignof您必须知道数据对齐的含义

很好的指南https://developer.ibm.com/articles/pa-dalign//

对齐(简而言之)

解释1

数据对齐意味着将数据放入内存中等于字大小的某个倍数的地址处。

解释2

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

CPU 执行对内存中存储的数据进行操作的指令。数据通过其在内存中的地址来标识。单个基准也有尺寸。如果数据的地址与其大小对齐,我们将其称为自然对齐的数据。否则称为错位。例如,如果用于标识 8 字节浮点数据的地址具有 8 字节对齐方式,则该数据自然是对齐的。

好的。您理解了“数据对齐” 恭喜!

这是什么意思alignas

解释

alignas (N)指定将仅将数据放置在 N 的倍数的地址中

N-以 2 的幂为模的数字

句法:

alignas( the numeric address modulo a power of 2 )
alignas( alignof(type-id) )
alignas( type-id )
Run Code Online (Sandbox Code Playgroud)

alignas 说明符可应用于:

  • class//structunion的声明或定义enumeration

  • 非位域类数据成员的声明;

  • 变量的声明,但它不能应用于以下情况

    • 函数参数;
    • catch 子句的异常参数。

例子:

struct alignas(256) name1 // every object of type name1 will be aligned to 256-byte boundary
{
    float test[4];
};

alignas(128) char name2[128]; // the array "name2" will be aligned to 128-byte boundary
Run Code Online (Sandbox Code Playgroud)

加法1

类型alignas说明符是一种可移植的 C++ 标准方法,用于指定变量和用户定义类型的自定义对齐方式。

加法2

#include <iostream>

struct alignas(16) Bar
{
    int i;       // 4 bytes
    int n;      // 4 bytes
    alignas(4) char arr[3];
    short s;          // 2 bytes
};

int main()
{
    std::cout << alignof(Bar) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

当遇到多个alignas说明符时,编译器将选择最严格的一个(值最大的那个)。

output: 16
Run Code Online (Sandbox Code Playgroud)

加法3

alignas不能用于为类型提供比没有此声明的类型更小的对齐方式

这是什么意思alignof

句法:

alignof( type-id )
Run Code Online (Sandbox Code Playgroud)

返回类型的值std::size_t

相同的定义有sizeof( type-id )

sizeof和 和有什么区别alignof

struct MyStruct
{
    int x;
    double y;
    char z;
};
    
main() 
{
    std::cout << "The sizeof(MyStruct): " << sizeof(MyStruct) << std::endl;
    std::cout << "The alignof(MyStruct): " << alignof(MyStruct) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
output:
    The sizeof(MyStruct): 24
    The alignof(MyStruct): 8
Run Code Online (Sandbox Code Playgroud)

结构填充问题

结构填充是C语言中的一个概念,它在内存地址之间添加一个或多个空字节以对齐内存中的数据

更多信息C++ 中的结构填充

添加

结果是类型为 的常量表达式std::size_t,即可以在编译时对其求值。

更多信息请参见: 来源 1来源 2