Стандарт не дает общего разрешения на доступ к объекту struct
или union
, используя lvalue типа члена, и, насколько я могу судить, не дает какого-либо конкретного разрешения на выполнение такого доступа, если толькочлен случается типа персонажа.Он также не определяет никаких средств, с помощью которых акт превращения int*
в union u*
может создать тот, который еще не существовал.Вместо этого создание любого хранилища, к которому когда-либо будет осуществляться доступ как union u
, подразумевает одновременное создание union u
объекта в этом хранилище.
Вместо этого Стандарт (ссылки, цитируемые в проекте C11 N1570)опирается на реализации для применения сноски 88 ( Цель этого списка - указать те обстоятельства, при которых объект может или не может иметь псевдоним. ) и признать, что "правило строгого наложения имен" (6.5p7)следует применять только тогда, когда на объект ссылаются как через lvalue его собственного типа, так и кажущееся несвязанным lvalue другого типа во время некоторого конкретного выполнения функции или цикла [т.е. когда объект псевдоним некоторого другого lvalue].
Вопрос о том, когда два значения могут рассматриваться как «кажущиеся не связанными» и когда реализация должна распознавать взаимосвязь между ними, является проблемой качества реализации.Clang и gcc, кажется, признают, что l-значения с формами unionPtr->value
и unionPtr->value[index]
связаны с *unionPtr
, но, похоже, не могут распознать, что указатели на такие l-значения имеют какое-либо отношение к unionPtr
.Таким образом, они распознают, что и unionPtr->array1[i]
, и unionPtr->array2[j]
обращаются *unionPtr
(поскольку подписка на массив через []
, похоже, трактуется иначе, чем затухание массива в указатель), но не распознает, что *(unionPtr->array1+i)
и *(unionPtr->array2+j)
сделать аналогично.
Приложение - стандартная ссылка:
Учитывая
union foo {int x;} foo,bar;
void test(void)
{
foo=bar; // 1
foo.x = 2; // 2
bar=foo; // 3
}
Стандарт будет описывать тип foo.x
как int
.Если второй оператор не имеет доступа к сохраненному значению foo
, то третий оператор не будет иметь никакого эффекта.Таким образом, второй оператор обращается к сохраненному значению объекта типа union foo
, используя lvalue типа int
.Глядя на N1570 6.5p7:
Доступ к сохраненному значению объекта должен осуществляться только через выражение lvalue, которое имеет один из следующих типов: (сноска 88)
- тип, совместимый с действительным типом объекта,
- квалифицированная версия типа, совместимого с действительным типом объекта,
- тип, который является типом со знаком или без знака, соответствующимк эффективному типу объекта:
- тип, который представляет собой тип со знаком или без знака, соответствующий квалифицированной версии действующего типа объекта,
- тип агрегирования или объединения, который включает одиниз вышеупомянутых типов среди его членов (включая, рекурсивно, член субагрегата или автономного объединения), или
- тип символа.
Сноска 88) Намерениев этом списке указываются те обстоятельства, при которых объект может иметь или не иметь псевдоним.
Обратите внимание, что для разрешенияЧтобы получить объект типа union foo
, используйте lvalue типа int
.Поскольку вышеприведенное является ограничением, любое его нарушение вызывает UB , даже если поведение конструкции в противном случае было бы определено стандартом .
.