Постоянная структура с гибкими элементами массива

Обратите внимание на следующие две структуры:

typedef struct { 
    int num_data;
    char * name_data;
    int data[]; 
} part_t; 
typedef struct { 
    int num_parts;
    char * name_parts;
    part_t parts[]; 
} container_t; 

В идеале я мог бы инициализировать контейнер примерно так:

const container_t container = { 
    2,
    "Name of first container", 
    { 
            { 4, "Name of first part", { 1, 2, 3, 4 } }, 
            { 5, "Name of first part", { 1, 2, 3, 4, 5 } } 
    } 
};

Мой компилятор говорит: "ошибка: слишком много инициализаторов"


person lupin3    schedule 04.12.2012    source источник
comment
Это даже не то, как работает простая структура переменной длины... Сначала попробуйте более простой пример.   -  person Kerrek SB    schedule 05.12.2012
comment
Это «гибкий элемент массива», а не VLA.   -  person Jonathan Leffler    schedule 05.12.2012
comment
Вкратце: вы не можете инициализировать гибкие элементы массива, а наличие массива struct с гибким элементом массива — это ожидающая катастрофа индексации.   -  person Daniel Fischer    schedule 05.12.2012
comment
@DanielFischer: Концептуально это не хуже, чем int foo[] = {1,2,3,4};, и я определенно сталкивался с местами, где такая вещь была бы полезна, если бы это было разрешено. Я не удивлюсь, если некоторые компиляторы разрешат такую ​​конструкцию, поскольку ясно, какой должна быть семантика для любого компилятора, который может ее обработать [выделить надлежащий объем пространства в области инициализированных данных, иметь имя структуры, представляющее lvalue в по адресу, и размер sizeof(structname) равен выделенному размеру]. Хотя эта функция была бы полезной, я не знаю, достаточно ли она полезна, чтобы оправдать ее реализацию.   -  person supercat    schedule 05.12.2012
comment
@supercat Я полагаю, вы говорите только об инициализации гибкого члена массива? Да, иногда это может быть полезно, но это будет означать, что тип зависит от длины члена гибкого массива, тогда у вас будет struct foo<N> (заимствование нотации шаблона C++). Если реализация поддерживает VLA, я полагаю, что это можно реализовать. Но это было бы нетривиальным изменением языка.   -  person Daniel Fischer    schedule 05.12.2012
comment
@DanielFischer: Моя точка зрения заключалась в том, что такая функция вряд ли была бы бессмысленной и не более катастрофической, чем некоторые другие функции, которые уже существуют. Я согласен с тем, что усилия, необходимые для его реализации, во многих случаях были бы достаточно высокими, чтобы предположить, что стандарт не должен требовать этого, но рассматривал бы его как разумное расширение компиляторов, конструкция которых допускала бы относительно простую реализацию.   -  person supercat    schedule 05.12.2012
comment
@supercat Если бы был разрешен массив структур с гибкими элементами массива, как бы вы его проиндексировали? Если бы гибкие члены массива составляли семейство типов с пареметром длины, struct foo<N> ar[12]; было бы нормально, как и массивы VLA. Но имея только один тип struct foo независимо от длины, которую вы задаете для гибкого элемента массива, что помешает вам вставлять в массив struct foo с разными длинами массива?   -  person Daniel Fischer    schedule 05.12.2012
comment
@DanielFischer: массивы переменной длины нельзя использовать в качестве элементов массива; это не изменило бы даже то, что можно было бы инициализировать во время компиляции и автоматически изменять размер структур с помощью VLA. Что касается определения размера, можно было бы либо иметь данные массива, заканчивающиеся дозорным значением, либо использовать sizeof() для определения размера массива, т.е. можно было бы использовать те же методы, которые использовались бы при использовании инициализированного массива автоматически определяемой длины .   -  person supercat    schedule 05.12.2012
comment
@supercat int dim; scanf("%d", &dim); if (dim < 1) exit(EXIT_FAILURE); double arr[15][dim]; нет проблем, массив из 15 VLA типа double[dim]. У меня такое чувство, что мы говорим мимо друг друга. struct foo { int bar; int baz[]; }; struct foo f1 = { 1, { 2,3,4 } }, f2 = { 2, { 5,6 } }; struct foo arr[12]; arr[0] = f1; arr[1] = f2; позже struct foo member = arr[i];, как это должно работать?   -  person Daniel Fischer    schedule 05.12.2012
comment
@DanielFischer: объявление arr завершится ошибкой. Можно сказать struct foo { int n; int baz[]; }; struct foo f1 = { 3, { 2,3,4 } }, f2 = { 2, { 5,6 } }; struct foo *arr[12]; arr[0]=&f1; arr[1] = &f2;. Человек, вводящий значение n для каждого экземпляра, будет нести ответственность за его соответствие размеру массива.   -  person supercat    schedule 12.12.2013
comment
@supercat У вас есть массив указателей на struct foo, это совершенно не проблематично. В лучшем случае будет сложно создать массив из struct foo, поскольку с гибким элементом массива вы не знаете, сколько байтов занимает каждый элемент массива.   -  person Daniel Fischer    schedule 12.12.2013
comment
@DanielFischer: типы структур с элементами гибкого массива не могут появляться в массивах, независимо от того, инициализированы они или нет. Я не вижу, чтобы я когда-либо говорил, что массивы структур, содержащих FLA, должны быть законными - просто инициализация структур, содержащих FLA, должна иметь возможность выделять столько места, сколько требуется для FLA.   -  person supercat    schedule 12.12.2013
comment
@supercat Я знаю. Язык явно запрещает это. Я думал, что вся эта болтовня была в том, что моя точка зрения заключалась в том, что такая функция вряд ли будет бессмысленной, и не более катастрофой, ожидающей своего появления, чем некоторые другие уже существующие функции, в которые вы не верили, что их допущение будет катастрофой индексации, ожидающей своего появления. , как я написал в своем первом комментарии, ссылаясь на массив структур part_t parts[]; OP с гибким элементом массива в container_t.   -  person Daniel Fischer    schedule 12.12.2013
comment
@DanielFischer: я имел в виду, что инициализация членов FLA концептуально не хуже, чем int foo[] = {1,2,3,4};. Мы согласны в отношении массивов FLA-содержащих структур.   -  person supercat    schedule 12.12.2013
comment
@supercat Столько шума из ничего, и мы часто неправильно понимали друг друга. Что ж, такое бывает. Существует небольшая разница между инициализацией гибких элементов массива и объявлением массива с неполным типом, поскольку структура с гибким элементом массива является полным типом, в то время как тип массива является полным только с измерением, и его тип определяется инициализатором. Так что с массивом тип дает вам (ну, не вам, реализации) размер, который для структур с гибкими членами массива не будет. Не непреодолимая проблема.   -  person Daniel Fischer    schedule 12.12.2013


Ответы (1)


ISO/IEC 9899:2011 §6.7.2.1 Структура и спецификаторы объединения

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

18 В качестве особого случая последний элемент структуры с более чем одним именованным элементом может иметь тип неполного массива; это называется гибким членом массива. В большинстве случаев гибкий элемент массива игнорируется. В частности, размер структуры такой же, как если бы элемент гибкого массива был опущен, за исключением того, что он может иметь больше замыкающего заполнения, чем предполагалось бы при пропуске. Однако, когда а. (или ->) имеет левый операнд, который является (указателем) структурой с гибким элементом массива, а правый операнд называет этот элемент, он ведет себя так, как если бы этот элемент был заменен самым длинным массивом (с тем же типом элемента ) это не сделало бы структуру больше, чем объект, к которому осуществляется доступ; смещение массива должно оставаться смещением гибкого элемента массива, даже если оно будет отличаться от смещения замещающего массива. Если этот массив не имеет элементов, он ведет себя так, как если бы он имел один элемент, но поведение не определено, если предпринимается какая-либо попытка получить доступ к этому элементу или сгенерировать указатель после него.

Проблема в том, что вы не можете встроить структуру с гибким элементом массива в массив или другую структуру. У вас могут быть указатели на такие структуры, но не экземпляры таких структур.

person Jonathan Leffler    schedule 04.12.2012
comment
Интересно, что CERT говорит, что структура с гибким элементом массива может использоваться как последний элемент другой структуры; но они не ссылаются на стандарт в этом пункте. Упоминается в пункте 3 пронумерованного списка: +flexible+array+member" rel="nofollow noreferrer">securecoding.cert.org/confluence/display/c/ - person hmijail mourns resignees; 17.10.2016
comment
Это обсуждается в органе по стандартизации C. См. N2083 из рассылки PrePittsburgh2016 на веб-сайте WG14. Пока это не законно; CERT в лучшем случае торопится. - person Jonathan Leffler; 17.10.2016
comment
Спасибо за этот указатель. Я прокомментировал документ CERT. - person hmijail mourns resignees; 17.10.2016
comment
Это выбор нит, но я думаю, что разрешено встраивать структуру с гибким элементом массива в объединение. Это не запрещено явно нигде, что я видел, и процитированный параграф 3 подразумевает, что это разрешено, когда в нем указано, что любой союз содержит, возможно, рекурсивно, член, который является такой структурой. - person ov2k; 01.09.2019
comment
Ниты заслуживают того, чтобы их выбрали, @ov2k, и это не исключение. Я думаю, вы, вероятно, правы; Я соответствующим образом изменил текст (а также исправил внешний вид). - person Jonathan Leffler; 01.09.2019