Можно ли найти выравнивание типа конструкции, если известно выравнивание элементов конструкции?
Например. для:
struct S
{
a_t a;
b_t b;
c_t c[];
};
это выравнивание S = max (alignment_of (a), alignment_of (b), alignment_of (c))?
Выполняя поиск в Интернете, я обнаружил, что «для структурированных типов наибольшее требование выравнивания любого из его элементов определяет выравнивание структуры» (в Что каждый программист должен знать о памяти ), но я не смог найти что-нибудь похожее в стандарте (точнее, последний проект).
Отредактировано:
Большое спасибо за все ответы, особенно Роберту Гэмблу, который дал действительно хороший ответ на первоначальный вопрос, и другим, кто внес вклад.
Короче говоря:
Чтобы обеспечить требования к выравниванию элементов конструкции, выравнивание конструкции должно быть как минимум таким же строгим, как выравнивание ее самого строгого элемента.
Что касается определения выравнивания структуры, было представлено несколько вариантов, и с небольшим исследованием это то, что я нашел:
- c ++ std :: tr1 :: alignment_of
- пока не стандартно, но близко (технический отчет 1), должно быть в C ++ 0x
- в последнем черновике присутствуют следующие ограничения: Предварительное условие: T должен быть полным типом, ссылочным типом или массивом
неизвестная граница, но не должна быть типом функции или (возможно,
cv-квалифицированный) void.
- это означает, что мой представленный вариант использования с гибким массивом C99 не будет работать (это не удивительно, поскольку гибкие массивы не являются стандартным c ++)
- в последнем черновом варианте c ++ он определен в терминах нового ключевого слова - alignas (это имеет такое же полное требование к типу)
- по моему мнению, если стандарт c ++ когда-либо будет поддерживать гибкие массивы C99, требование может быть ослаблено (выравнивание структуры с гибким массивом не должно изменяться в зависимости от количества элементов массива)
- c ++ boost :: alignment_of
- в основном замена tr1
- , кажется, специализируется на void и возвращает 0 в этом случае (это запрещено в проекте c ++)
- Примечание от разработчиков: строго говоря, вы должны полагаться только на значение ALIGNOF (T), кратное истинному выравниванию T, хотя на практике оно вычисляет правильное значение во всех случаях, о которых мы знаем.
- Я не знаю, работает ли это с гибкими массивами, оно должно (может не работать вообще, это разрешает встроенную функцию компилятора на моей платформе, поэтому я не знаю, как оно будет вести себя в общем случае)
- Эндрю Топ представил простое шаблонное решение для расчета выравнивания в ответах
- кажется, что это очень близко к тому, что делает повышение (повышение будет дополнительно возвращать размер объекта в качестве выравнивания, если оно меньше расчетного выравнивания, насколько я могу видеть), так что, вероятно, применимо то же самое замечание
- это работает с гибкими массивами
- используйте Windbg.exe, чтобы узнать выравнивание символа
- не время компиляции, не зависит от компилятора,
- использование offsetof для анонимной структуры, содержащей тип
- см. Ответы, ненадежные, не переносимые с C ++ non-POD
- встроенные функции компилятора, например. MSVC __alignof
- работает с гибкими массивами
- ключевое слово alignof в последней версии c ++
Если мы хотим использовать «стандартное» решение, мы ограничены std :: tr1 :: alignment_of, но это не сработает, если вы смешаете свой код c ++ с гибкими массивами c99.
На мой взгляд, есть только 1 решение - используйте старый взлом структуры:
struct S
{
a_t a;
b_t b;
c_t c[1]; // "has" more than 1 member, strictly speaking this is undefined behavior in both c and c++ when used this way
};
Расхождения в стандартах c и c ++ и их растущие различия неутешительны в этом случае (и во всех других случаях).
Еще один интересный вопрос (если мы не можем выяснить выравнивание структуры переносимым способом), каково наиболее строгое требование выравнивания из возможных. Я смог найти пару решений:
- boost (внутренне) использует объединение различных типов и использует для него boost :: alignment_of
- последний черновой вариант c ++ содержит std :: align_storage
- Значение default-alignment должно быть самым строгим требованием выравнивания для любого типа объекта C ++, размер которого не превышает Len
- поэтому
std::alignment_of< std::aligned_storage<BigEnoughNumber>>::value
должен дать нам максимальное выравнивание
- только черновик, еще не стандарт (если вообще),
tr1::aligned_storage
не имеет этого свойства
Любые мысли по этому поводу также будут оценены.
Я временно снял флажок с принятым ответом, чтобы получить больше информации о новых подвопросах и ввести их в него