Я не думаю, что авторы Стандарта когда-либо достигли консенсуса в отношении того, какие конструкции должны требовать или, как ожидается, будут вести себя с пользой при каких обстоятельствах. Вместо этого они рассматривают проблему как вопрос «качества реализации», полагаясь на реализации, поддерживающие любые конструкции, которые могут понадобиться их клиентам.
Стандарт C указывает, что чтение объекта объединения через член, отличный от последний записанный член будет интерпретировать байты, используя новый тип. Однако, если взглянуть на список типов lvalue, которые могут быть использованы для доступа к объектам структуры или объединения, то нет никаких условий для доступа к структурам или объединениям, использующим объекты не символьных типов-членов. В большинстве случаев, когда будет использоваться указатель или lvalue типа-члена, он будет явно заново получен из указателя или lvalue на родительский тип, и если компилятор предпримет какие-либо разумные усилия, чтобы заметить такой вывод, будет нет необходимости в общем правиле, допускающем использование этих типов. Вопрос о том, когда признавать такой вывод, был оставлен в качестве вопроса качества реализации при условии, что компиляторы, которые предприняли какие-либо добросовестные усилия для удовлетворения потребностей своих клиентов, вероятно, справились бы лучше, чем если бы Стандарт пытался выписать набор точных правил.
Вместо того, чтобы пытаться найти способы, с помощью которых указатели типа элемента могут быть получены из объектов struct или union, g cc и clang вместо этого выбирают go сверх того, что на самом деле указано в гораздо меньшей степени, чем ожидали бы большинство членов комитета. Они будут обрабатывать операцию, выполненную непосредственно над lvalue, сформированным с использованием value.member
или ptr->member
, - это операция над родительским объектом. Они также распознают l-значения вида value.member[index]
или ptr->member.index
. С другой стороны, несмотря на то, что (array)[index]
определено как эквивалентное (*((array)+(index)))
, они не будут распознавать (*((ptr->member)+(index)))
как операцию над объектом, обозначенным ptr
. Они также, как правило, без необходимости будут предполагать, что объекты структурного типа могут взаимодействовать с не связанными указателями на объекты типа члена.
Если кто-то пишет код, который выиграл бы от возможности выполнять штампование типов, моя рекомендация будет явно указать в документации, что для надежной работы требуется -fno-strict-aliasing
. Цель правил наложения имен состояла в том, чтобы дать авторам компилятора свободу выполнять оптимизацию , которая не мешала бы тому, что их клиенты должны были сделать . Авторы компиляторов должны были распознавать и поддерживать потребности своих клиентов, независимо от того, требовал ли он от них этого.