Как удобно расположить массив структур с гибкими членами массива? - PullRequest
2 голосов
/ 03 апреля 2019

У меня есть следующая структура с гибким членом массива:

struct test {
    size_t sz;
    const char str[];
};

Теперь я хочу выделить немного памяти для размещения этой структуры непрерывно (как в массиве).Проблема в том, что объявление типа struct test test_arr[] не определено.6.7.2.1(p3):

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

Мы знаем, что указатель, возвращаемыйmalloc можно преобразовать в указатель на любой тип объекта с фундаментальным выравниванием.Рассмотрим следующий код:

void *obj= malloc(100 * sizeof(struct test)); //enough memory
struct test *t1 = obj;
t1 -> sz = 2;
t1 -> str = {'a', 'b'};
struct test *t2 = (void *) (((char *) obj) + sizeof(struct test) + sizeof(char[2])); // non conforming 

Каков соответствующий способ сделать это?

Ответы [ 2 ]

3 голосов
/ 03 апреля 2019

A struct с членом гибкого массива не может быть членом массива, как это указано в приведенной вами цитате.

Лучший способ справиться с этим - изменить элемент гибкого массива науказатель и выделите для него место отдельно.

struct test {
    size_t sz;
    char *str;
};

...

struct test *arr = malloc(100 * sizeof(struct test));

arr[0].sz = 2;
arr[0].str = malloc(2);
arr[0].str[0] = 'a';
arr[0].str[1] = 'b';

arr[1].sz = 3;
arr[1].str = malloc(3);
arr[1].str[0] = 'c';
arr[1].str[1] = 'd';
arr[1].str[2] = 'e';

Кроме того, обычно не рекомендуется иметь const членов структуры.

1 голос
/ 05 апреля 2019

«Популярное расширение», которое может быть сконфигурировано для поддержки большинства реализаций (если они не всегда делают это), состоит в том, чтобы разрешить преобразование адреса типа структуры в адрес другого, который имеет общую начальную последовательность, ииспользоваться для доступа к членам этой последовательности до тех пор, пока структура не будет доступна с помощью средств, отличных от преобразованного указателя, или пока выполнение не войдет в функцию или цикл, в котором это произойдет.

В реализациях, которые поддерживают это расширение, запрошенная семантикаможет быть достигнуто путем объявления структуры, макет которой соответствует структуре структуры, с элементом Flexible Array.Например:

struct POINT { int x, y; };
struct POLYGON { int sides; struct POINT coords[]; };
struct TRIANGLE { int sides; struct POINT coords[3]; };

void draw_polygon(struct POLYGON const *p);
void test(void)
{
  struct TRIANGLE my_triangle = {3, {{1,2}, {3,4], {5,6}};
  draw_polygon((struct POLYGON*)&my_triangle);
}

Некоторые компиляторы, такие как icc и MSVC, достаточно продвинуты, чтобы поддерживать это расширение, даже если включен псевдоним на основе типа.Другие, такие как gcc и clang, могут поддерживать это расширение только с помощью опции -fno-strict-aliasing.

Хотя код, использующий это расширение, не совсем соответствует, Комитет по стандартам заявил в опубликованном Обосновании, что они не хотятсделать язык доступным только для написания переносимых программ.Вместо этого они ожидали, что качественные реализации будут поддерживать различные «популярные расширения», обрабатывая некоторые конструкции способами, которые будут полезны для их клиентов, даже если стандарт позволит им поступить иначе.Способность конвертировать указатели между типами структур была фундаментальной частью языка, который Стандарт был описан для описания с 1974 года, и почти все реализации могут быть сконфигурированы для его поддержки.Таким образом, код, подобный приведенному выше, должен распознаваться как более переносимый, чем код, использующий нестандартные синтаксические расширения для достижения аналогичной семантики.

...