Объединение с анонимной структурой с гибким членом массива - PullRequest
14 голосов
/ 05 июня 2019

Рассмотрим следующие два примера:

1

union test{
  struct {
      int a;
      int b[];
  };
};


int main(void){
    union test test;
    test.a = 10;
    printf("test.b[0] = %d", test.b[0]); //prints 0, UB?
}

DEMO

2

#include <stdio.h>

union test{
    int a;
    int b[]; //error: flexible array member in union
};


int main(void){
    union test test;
    test.a = 10;
    printf("test.b[0] = %d", test.b[0]);
}

DEMO

Поведение неясно. Я ожидал, что примеры будут вести себя одинаково (то есть первый пример также не сможет скомпилироваться), так как 6.7.2.1(p13):

Члены анонимной структуры или союза считаются члены вмещающей структуры или объединения.

Таким образом, я интерпретировал формулировку так, как если бы union содержал анонимный struct в качестве члена, члены анонимного struct считались бы членами содержащего union.

Вопрос : Почему первый пример компилируется нормально, а не как второй?

Ответы [ 4 ]

13 голосов
/ 05 июня 2019

Члены анонимной структуры или объединения считаются членами содержащей структуры или объединения.

Это сложное положение для интерпретации, и оно действительно было предметомпо крайней мере два сообщения о дефектах по сравнению со стандартом.Цель, подтвержденная комитетом в его ответе на DR 499 , заключается в том, что анонимные структуры обрабатываются в целях компоновки, как если бы сама структура была членом содержащей структуры или объединения, но access для его членов выражается так, как если бы они были членами содержащей структуры или объединения.

Принятая позиция в DR 502 , с другой стороны, считает, что даже анонимная структура, содержащаядопускается использование элемента гибкого массива в качестве его only , если он является последним членом структуры (не union), содержащей его, и по крайней мере один другой предшествует ему.

Я нахожу эти aНемного противоречиво, но объединяющая их тема, похоже, заключается в том, что цель стандарта в этой области сводится к layout .Элемент гибкого массива внутри анонимной структуры допускается, если он находится в конце макета самой внутренней именованной структуры или объединения, который должен иметь ненулевой размер по сравнению с другими членами, принимая во внимание тот факт, что членыанонимной структуры не перекрываются, независимо от того, появляется ли анонимная структура внутри объединения.

6 голосов
/ 05 июня 2019

Стандарт (C11) гласит в §6.7.2.1 Спецификаторы структуры и объединения *3 - ограничение:

¶3 Структура или объединение не должны содержать члена с неполным или функциональным типом (следовательно, структура не должна содержать своего экземпляра, но может содержать указатель на свой экземпляр), за исключением того, что последний член структура с более чем одним именованным членом может иметь неполный тип массива; такая структура (и любое объединение, содержащее, возможно, рекурсивно член, являющийся такой структурой) не должно быть членом структуры или элементом массива.

Обратите внимание, что только структуры могут (напрямую) содержать член гибкого массива - объединения не могут.

Первый случай законен. Второе нет.

(Это §6.7.2.1 ¶18 , который определяет термин элемент гибкого массива .)

Между прочим, в первой версии вопроса оператор printf() в первом примере обращался к элементу массива, который не был выделен - дефект, который с тех пор был исправлен в ревизии 2 Запись union test test; дает вам массив размером 0. Вы должны использовать динамическое выделение памяти (или какой-либо другой механизм ), чтобы выделить объединение или структуру с достаточным пространством для не пустой FAM. Аналогичные комментарии применимы и ко второму примеру.

Некоторое имя говорится в комментарии

Но поскольку в первом случае структура является анонимной, поэтому члены структуры должны рассматриваться как члены содержащего объединения, в котором объединение содержит элемент гибкого массива. Как я цитировал Члены анонимной структуры или объединения считаются членами содержащей структуры или объединения.

Обратите внимание, что анонимная структура не теряет свою форму только потому, что она встроена в объединение. Одно из отличий состоит в том, что смещение b в union test не может быть 0, что полностью отличается от нормальных членов объединения. Обычно все члены объединения начинаются со смещения 0. В основном, это говорит о том, что с учетом переменной union test u; вы можете ссылаться на u.a и u.b. В прошлом вам приходилось указывать имя для структуры: union test { struct { int a; int b[]; } s; }; и использовать u.s.a или u.s.b для доступа к элементам структуры в объединении. Это не влияет на то, где допускается использование гибкого элемента массива; только обозначение, используемое для доступа к нему.

6 голосов
/ 05 июня 2019

Во втором случае не удается скомпилировать, потому что гибкий член массива является свойством структурного типа, а не для объединений.Это просто.

Далее, в первом случае попытка доступа к b[0] была бы неопределенным поведением, так как для этого не было выделено памяти.

Цитирование C11, §6.7.2.1 / P18

В особом случае последний элемент структуры с более чем одним именованным элементом может иметь неполный тип массива;это называется членом гибкого массива.[...] Если этот массив не имеет элементов, он ведет себя так, как если бы он имел один элемент, но поведение не определено, если предпринята какая-либо попытка получить доступ к этому элементу или сгенерировать указатель один за ним.

При этом

Члены анонимной структуры или объединения считаются членами содержащей структуры или объединения.

То есть для цели доступа макет остается неизменным.В первом примере вы видите, что вы получаете доступ к ab), как если бы они были прямыми членами союза.

Чтобы уточнить,

#include <stdio.h>

union test{
    struct {
        int p;
        float q;
    } t;                //named structure member
  struct {
      int a;
      int b[];
  };
    char pqr;
};


int main(void){
    union test test;
    test.t.p = 20;   // you have to use the structure member name to access the elements
    test.pqr = 'c';     // direct access, as member of union
    test.a = 10;        // member of anonymous structure, so it behaves as if direct member of union
}
3 голосов
/ 05 июня 2019

Конечно, всегда предполагалось, что непомеченные композиты в анонимном композите сохранят свою форму.Но это не было ясно в формулировке §6.7.2.1p13.Формулировка была изменена в олове C18: (выделено):

Безымянный член, спецификатор типа которого является структурным спецификатором без тега, называется анонимной структурой;неназванный член, спецификатор типа которого является спецификатором объединения без тега, называется анонимным объединением.Члены анонимной структуры или объединения считаются членами содержащей структуры или объединения, сохраняя свою структуру или структуру объединения .Это применяется рекурсивно, если содержащая структура или объединение также являются анонимными.

См. http://www.iso -9899.info / wiki / The_Standard для ссылок на стандарт C18 и черновик в свободном доступе (pdf)

...