C: рекомендуемый стиль для динамических размеров конструкций - PullRequest
9 голосов
/ 26 мая 2009

Мне нужно передавать пакеты через Интернет, длина которых должна быть динамической.

struct packet
{
  int id;
  int filename_len;
  char filename[];
};

Проблема в том, что массивы нулевой длины не соответствуют ISO.

Должен ли я использовать char filename[1]; вместо этого? Но тогда sizeof(struct packet) больше не вернет правильное значение.

Ответы [ 4 ]

6 голосов
/ 26 мая 2009

Классический выпуск. Вы можете просто справиться с этим (и заметить, что sizeof (foo) может быть отключен более чем на единицу, если компилятор округляет размер структуры, что разрешено), или вы можете сделать что-то вроде этого:

struct packetheader {
   int id;
   int filename_len;
};
struct packet {
   struct packetheader h;
   char filename[1];
};

Это раздражает (вы должны использовать h.id и т. Д.), Но это работает. Обычно я имею дело с тем, что он один, но вышеперечисленное может быть несколько более портативным.

6 голосов
/ 26 мая 2009

Я думаю, что вы должны взглянуть на некоторые существующие примеры динамически изменяемых структур для руководства здесь. Лучший пример, который я знаю, это API-интерфейсы TOKEN в Win32. Они используют макрос ANYSIZE_ARRAY, который просто разрешается до 1. Раймонд Чен написал обширную статью в блоге, подробно описывающую, почему они так поступили

Что касается операций, таких как sizeof сбой. Это не удастся, независимо от того, какое решение вы выберете для структуры динамического размера. sizeof - это операция времени компиляции, и вы будете изменять размер структуры во время выполнения. Это просто не может работать.

4 голосов
/ 26 мая 2009

Я предлагаю использовать char filename[1] и включать завершающий 0-байт. Таким образом, вы можете malloc() правильный размер структуры и избежать одноразовых ошибок, таких как:

ptr = malloc(sizeof(struct packet)+filename_len);
strncpy(&ptr->filename, filename, filename_len);

Но получатель должен знать, что ему нужно прочитать filename_len+1 байт.

3 голосов
/ 26 мая 2009

Действительно массивы нулевой длины не являются частью стандарта. Но в вашем фрагменте кода есть гибкий массив, являющийся частью стандарта ISO C99. Если бы вы могли использовать C99, я бы использовал гибкий массив, если бы не предложение jesup, вероятно, лучшее.

...