Гибкий член массива в C-структуре - PullRequest
5 голосов
/ 15 июня 2010

Цитирование из раздела C-std 6.7.2.1,

struct s { int n; double d[]; };

Это допустимое объявление структуры.Я ищу практическое использование этого вида синтаксиса.Чтобы быть точным, как эта конструкция может быть более или менее мощной, чем сохранение двойного * как 2-го элемента?Или это еще один случай «вы можете сделать это несколькими способами»?

Arpan

Ответы [ 4 ]

10 голосов
/ 15 июня 2010

FAQ C отвечает именно на этот вопрос.Быстрый ответ состоит в том, что эта структура будет включать массив double внутри структуры, а не указатель на массив вне структуры.В качестве быстрого примера вы можете использовать свою структуру, как в этом примере:

struct s mystruct = malloc(sizeof(struct s) + 5 * sizeof(double));
s.n = 12;
s.d[0] = 4.0;
s.d[1] = 5.0;
s.d[2] = 6.0;
s.d[3] = 7.0;
s.d[4] = 8.0;

И так далее - размер массива, который вам нужен, включен в выделение, и затем вы можете использовать его так же,любой массив.Обычно такой тип содержит размер как часть структуры, поскольку использование трюка + для пропуска массива типа s будет обязательно осложнено этой ситуацией.

К добавленному вами вопросу 'какэта конструкция более или менее мощная, чем сохранение [указателя] в качестве 2-го элемента? ', она не более мощная сама по себе, но вам не нужно держать указатель вокруг, поэтому вы должны сохранитьпо крайней мере, так много места - также, когда вы копируете структуру, вы также копируете массив, а не указатель на массив - иногда небольшая разница, но очень важная в других случаях.«Вы можете сделать это несколькими способами», вероятно, является хорошим объяснением, но есть случаи, когда вам определенно нужен один или другой дизайн.

4 голосов
/ 15 июня 2010

Основным преимуществом является то, что гибкий член массива позволяет вам выделить один блок памяти для массива вместе с другими данными в структуре (с указателем, вы обычно заканчиваетедва отдельно выделенных блока).

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

2 голосов
/ 15 июня 2010

Вы можете использовать его для добавления полей заголовка к динамически размещаемым массивам, наиболее распространенным из которых будет его размер:

struct int_array
{
    size_t size;
    int values[];
};

struct int_array *foo = malloc(sizeof *foo + 42 * sizeof *foo->values);
foo->size = 42;

...

for(size_t i = 0; i < foo->size; ++i)
    foo->values[i] = i * i;

Подобные результаты можно получить, используя вместо этого элемент int * ивыделять массив отдельно, но он будет менее эффективен как с точки зрения памяти (дополнительный указатель, управление кучей для 2-го блока памяти), так и времени выполнения (дополнительное косвенное обращение, 2-е выделение).

0 голосов
/ 15 июня 2010

Я видел, как это используется в Windows для строк, которые помечены по их длине.Данные символов сохраняются непосредственно после длины в памяти, сохраняя все вместе аккуратно.

typedef struct {
    SIZE_T bytes;
    TCHAR chars[];
} tagged_string;
...