Как массив выровнен в C++ по сравнению с содержащимся типом?
Предположим, у меня есть какой-то тип T
это должно быть N
байты выровнены. Теперь я объявляю массив типа T
:
T array[size];
Будет ли массив иметь те же требования к выравниванию, что и тип T
или у него будут другие требования по выравниванию?
4 ответа
Да, требования к выравниванию должны быть одинаковыми. Очевидно, массив T
должны быть выровнены по крайней мере так же строго, как один T
в противном случае его первый член не будет правильно выровнен. Тот факт, что массив не может быть выровнен более строго, чем его тип элемента, следует из стандартного раздела 8.3.4, в котором говорится, что массивы являются смежно распределенными подобъектами элементов. Рассмотрим этот массив массивов:
T a[2][size];
Какой бы ни была ценность size
, не может быть никакого "дополнительного" заполнения между двумя массивами a[0]
а также a[1]
в противном случае это нарушает смежно распределенное требование.
Эквивалентно, мы знаем, что (char*)&a[1] == (char*)&a[0] + sizeof(a[0])
а также sizeof(a[0]) == sizeof(T[size]) == size * sizeof(T)
, Как это верно для любого size
должно быть возможно разместить массив T
по любому адресу, который выровнен для одного T
объект (при условии адекватного адресного пространства).
Я считаю, что требования к выравниванию массива будут идентичны требованиям к элементам массива.
Очевидно, что начало массива должно быть выровнено, по крайней мере, так строго, как этого требует его первый элемент, поэтому его требования к выравниванию не могут быть менее строгими.
Начальный адрес массива плюс размер каждого элемента должны оставлять второй элемент достаточно выровненным. Это накладывает ограничение на размер типа элемента, что, как я считаю, означает, что заполнение может быть введено в конце структуры, просто чтобы выровнять массивы, даже если вы никогда не используете эту структуру в массиве. Но это не значит, что есть необходимость в более строгом выравнивании.
По индукции последующие элементы в порядке, если первые два в порядке, поэтому для массива должны быть установлены те же требования к выравниванию, что и для его элементов.
Хотя цитата из спецификации была бы хороша.
Правила те же, я верю, но толкование может сбить с толку.
Я полагал, что, поскольку каждый элемент массива будет иметь одинаковый размер, поэтому только выравнивание первого элемента автоматически выровняет остальные, и, следовательно, между элементами никогда не будет заполнения.
Это может быть верно в случае тривиального массива, но не для сложных сценариев.
Шаг массива может быть больше, чем размер элемента, т. Е. Между отдельными элементами могут быть площадки.
Ниже приведен хороший пример
struct ThreeBytesWide {
char a[3];
};
struct ThreeBytesWide myArray[100];
источник - пошаговая википедия
Каждый элемент массива ThreeBytesWide может быть выровнен по четырехбайтовой границе
Редактировать: Как уточняется в комментариях, упоминание наличия площадок между отдельными элементами - это когда сам элемент имеет, скажем, 3 байта и выровнен по границе четырех байтов.
Массив объектов должен быть смежным, поэтому между объектами никогда не бывает заполнения, хотя заполнение может быть добавлено к концу объекта (производя почти такой же эффект). Выравнивание элементов данных C++ и упаковка массивов
#include <iostream>
__declspec(align(32))
struct Str1
{
int a;
char c;
};
template<typename T>
struct size
{
T arr[10];
};
int main()
{
size<Str1> b1;
std::cout << sizeof(Str1) << std::endl; // prints 32
std::cout << sizeof(b1) << std::endl; // prints 320
std::cin.ignore();
return 0;
}
Рекомендации: