Как массив выровнен в 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;
}

Рекомендации:

  1. Выравнивание данных в C++, стандарт и переносимость
  2. http://msdn.microsoft.com/en-us/library/83ythb65.aspx
Другие вопросы по тегам