Как выровнять данные, содержащиеся в std:: array?
С 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;
}
предоставляет следующие выходные данные, которые показывают, что данные контейнера выровнены по 16-байтовым адресам независимо от типа данных, содержащихся при компиляции для архитектуры x86-64 бит.
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-байтовым адресам, некоторые (char
и float
массивы) выровнены по меньшим байтовым адресам (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 от Intel.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
1 ответов
по умолчанию компилятор будет делать правильные вещи, когда дело доходит до выравнивания.
но вы можете переопределить его с alignas
:
alignas(16) std::array<char, 10> b;
Postscriptum
интересно, что компилятор Intel считает, что достаточно выровнять char[]
на 8 байт. Как будто это знает что на платформе x86 вы мало выигрываете, выравнивая ее пошире.
имейте в виду, что слишком много выравнивание может уменьшить производительность из-за увеличения использования памяти и снижения эффективности кэша. Современные архитектуры x86 (Sandy Bridge и новее) очень эффективно работают с несогласованными данными, но не могут компенсировать частично используемые строки кэша (подробнее).