Вопрос по поводу спецификатора alignas
С помощью спецификатора alignas можно явно задать необходимое выравнивание для объекта. Пример:
alignas(short) alignas(long long) int a;
Здесь среди всех спецификаторов alignas, применённых к переменной a, будет использоваться самое строгое требование по выравниванию.
Но есть один момент, смысл которого мне не ясен. Если самое строгое требование по выравниванию среди всех спецификаторов alignas, слабее, чем собственное требование по выравниванию типа переменной a, то программа считается неправильной. Это требование стандарта языка. Пример:
alignas(short) int a; //Ошибка.
Если требования по выравниванию у типа short слабее, чем требования по выравниванию для типа int (так оно обычно и бывает на практике), то приведённый выше код является неправильным.
Почему стандарт языка хочет, чтобы приведённый код был ошибочным? Почему бы просто не проигнорировать спецификатор alignas(short), если требование по выравниванию у типа int строже чем у типа short? Ведь предыдущий пример я могу переписать так:
alignas(short) alignas(int) int a;
Ответы (1 шт):
Один из самых ранних черновиков, который мне удалось найти, и в котором обсуждается введение требований по выравниванию в стандарт языка — это документ от 2002 года: n1546 — Alignment Proposal. Вот цитата оттуда:
The alignment-specifier can be used in variable declarations just like a storage-class-specifier. It can be used portably to specify the alignment requirement for the variable being declared.
In general alignment requirement for a type can be strengthened, weakened or unchanged. Open question is whether it makes any sense to weaken the alignment requirements. The only place where it seems to be useful is the creation of “packed” class types. Since on many platforms accessing a misaligned variable is very costly and “packing” is not directly related to alignment I propose not to allow weakening.
Из написанного следует, что спецификатор выравнивания обязателен к выполнению. Т.е. конструкция
alignas(short) int a;
означает, не только то, что переменная a должна быть выравнена по типу short, но и то, что она не обязана быть выравнена по типу int. Т.к. на практике доступ к невыравненной переменной может быть проблематичен, было принято решение, запретить ослабление требований по выравниванию:
If the alignment-specifier would weaken the alignment requirement of the type, the program is ill-formed and diagnostics are required
C тех пор смысл спецификатора выравнивания немного изменился. Да, он всё ещё требует, чтобы объект удовлетворял запрашиваемому выравниванию, но теперь спецификатор выравнивания не отменяет более строгие требования по выравниванию. То есть здесь:
alignas(short) alignas(int) alignas(long long) int a;
спецификатор alignas(short) не отменяет требований спецификаторов alignas(int) и alignas(long long), а спецификатор alignas(int) не отменяет требование спецификатора alignas(long long).
Тем не менее, писать так:
alignas(char) alignas(short) int a;
всё ещё нельзя. Среди спецификаторов выравнивания должен найтись хотябы один, который запрашивает выравнивание не слабее, чем то выравнивавние, которое было бы у переменной a, если бы она не имела никаких спецификаторов выравнивания.
По сути это требование стандарта сохранилось со времён того самого черновика от 2002 года, хотя формулировка немного изменилась (dcl.align/5):
The combined effect of all alignment-specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would be required for the entity being declared if all alignment-specifiers appertaining to that entity were omitted.
В документе-обсуждении от 2020 года P2152R0 — Querying the Alignment of an Object — рассматривается вариант игнорирования запроса на более слабое выравнивание. Но этот вариант не рекомендуется, т.к. он нарушает совместимость с языком C и игнорирование явного запроса на выравнивание — это спорное решение:
Add that describing a weaker alignment for an object than required by its objecttype will be ignored.
...
the suggestions are for behaviour weaker than of C’s struct, and will increase the difference between the languages regarding the struct keyword, as well as ignore the alignment explicit demand, therefore I don’t recommend it.
Для того, чтобы быть уверенным, что запрашиваемое выравнивание A не слабее, чем собственное выравнивание у некоторого объекта типа T, стандарт языка рекомендует добавить к запрашиваемому выравниванию ещё и alignas(T) (dcl.align/7):
[Example 3: An aligned buffer with an alignment requirement of
Aand holdingNelements of typeTcan be declared as:alignas(T) alignas(A) T buffer[N];Specifying
alignas(T)ensures that the final requested alignment will not be weaker thanalignof(T), and therefore the program will not be ill-formed. — end example]