如何对齐std::数组中包含的数据

How to align std::array contained data?

本文关键字:数组 数据 包含 std 何对齐 对齐      更新时间:2023-10-16

由于std::array不允许更改其分配器,是否有一种方法可以确保指向数据地址的指针对齐?

例如,在GNU g++ 4.8.4和6.1.0中,

下面的代码
#include <array>
#include <iostream>
int main(void)
{
  std::array<bool, 10> a;
  std::array<char, 10> b;
  std::array<int,10> c;
  std::array<long long, 10> d;
  std::array<float, 10> e;
  std::array<double, 10> f;
  std::cout << "array<bool,10>.data()       = " << a.data() << std::endl;
  std::cout << "array<char,10>.data()       = " << (void*) b.data() << std::endl;
  std::cout << "array<int,10>.data()        = " << c.data() << std::endl;
  std::cout << "array<long long, 10>.data() = " << d.data() << std::endl;
  std::cout << "array<float, 10>.data()     = " << e.data() << std::endl;
  std::cout << "array<double, 10>.data()    = " << f.data() << std::endl;
  return 0;
}

提供了以下输出,显示在为x86-64位体系结构编译时,无论包含的数据类型如何,容器数据都对齐到16字节地址。

array<bool,10>.data()       = 0x7ffe660a2e40
array<char,10>.data()       = 0x7ffe660a2e30
array<int,10>.data()        = 0x7ffe660a2e00
array<long long, 10>.data() = 0x7ffe660a2db0
array<float, 10>.data()     = 0x7ffe660a2d80
array<double, 10>.data()    = 0x7ffe660a2d30

然而,对于Intel的icpc v16.0.3,即使使用-align,结果也如下所示。虽然大多数容器都对齐到16字节地址,但有些容器(charfloat数组)对齐到较小的字节地址(分别为2字节和8字节)。

array<bool,10>.data()       = 0x7ffdedcb6bf0
array<char,10>.data()       = 0x7ffdedcb6bfa
array<int,10>.data()        = 0x7ffdedcb6ba0
array<long long, 10>.data() = 0x7ffdedcb6b00
array<float, 10>.data()     = 0x7ffdedcb6bc8
array<double, 10>.data()    = 0x7ffdedcb6b50

编辑

只是为了举例说明来自RustyX的提议,这是修改后的代码

#include <array>
#include <iostream>
int main(void)
{
  alignas(16) std::array<bool, 10> a;
  alignas(16) std::array<char, 10> b;
  alignas(16) std::array<int,10> c;
  alignas(16) std::array<long long, 10> d;
  alignas(16) std::array<float, 10> e;
  alignas(16) std::array<double, 10> f;
  std::cout << "array<bool,10>.data()       = " << a.data() << std::endl;
  std::cout << "array<char,10>.data()       = " << (void*) b.data() << std::endl;
  std::cout << "array<int,10>.data()        = " << c.data() << std::endl;
  std::cout << "array<long long, 10>.data() = " << d.data() << std::endl;
  std::cout << "array<float, 10>.data()     = " << e.data() << std::endl;
  std::cout << "array<double, 10>.data()    = " << f.data() << std::endl;
  return 0;
}

,这是在英特尔的icpc v16.0.3中编译它的结果。

array<bool,10>.data()       = 0x7ffe42433500
array<char,10>.data()       = 0x7ffe42433510
array<int,10>.data()        = 0x7ffe424334a0
array<long long, 10>.data() = 0x7ffe42433400
array<float, 10>.data()     = 0x7ffe424334d0
array<double, 10>.data()    = 0x7ffe42433450

默认情况下,当涉及到对齐时,编译器会做正确的事情。

但是你可以用alignas:

覆盖它
alignas(16) std::array<char, 10> b;

附启

有趣的是,Intel编译器认为在8字节上对齐char[]就足够了。就好像它知道在x86平台上把它对齐得再宽也不会有什么好处。

请记住,过多的对齐会降低性能,因为这会增加内存使用和降低缓存效率。现代x86架构(Sandy Bridge和更新版本)在处理未对齐的数据时非常有效,但无法补偿部分使用的缓存线(更多信息)。