C: Рекомендуемый стиль для структур с динамическим размером

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

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

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

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


person codymanix    schedule 26.05.2009    source источник


Ответы (4)


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

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

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

person jesup    schedule 26.05.2009

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

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

person JaredPar    schedule 26.05.2009
comment
под sizeof я имел в виду именно размер структуры, а не динамического поля, потому что при получении UDP-пакета я сначала читаю структуру, содержащую размер динамического поля, а затем читаю динамическое поле. - person codymanix; 26.05.2009

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

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

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

person Aaron Digulla    schedule 26.05.2009

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

person quinmars    schedule 26.05.2009