Чтение неинициализированных массивов unsigned int из пакета в C

Я застрял с проблемой чтения байтов на моем сервере сокетов C tcp, который получает запрос от клиента python. У меня есть следующая структура в качестве моего шаблона получения

struct ofp_connect {
uint16_t wildcards;                /* identifies ports to use below */
uint16_t num_components;           

uint8_t  pad[4];                   /* Align to 64 bits */

uint16_t in_port[0];               
uint16_t out_port[0];           

struct ofp_tdm_port in_tport[0];   
struct ofp_tdm_port out_tport[0];

struct ofp_wave_port in_wport[0];  
struct ofp_wave_port out_wport[0];

};
OFP_ASSERT(sizeof(struct ofp_connect) == 8);

Я могу правильно прочитать первые два 32-битных поля, но моя проблема заключается в том, что in_port[0] после поля заполнения кажется неправильным. То, как его в настоящее время читают,

uint16_t portwin, portwout, * wportIN;
wportIN =  (uint16_t*)&cflow_mod->connect.in_port; //where cflow_mod is the main struct which encompasses connect struct template described above 
memcpy(&portwin, wportIN, sizeof(portwin) );
DBG("inport:%d:\n", ntohs(portwin));

к сожалению, это не дает мне ожидаемого номера порта. Я могу проверить в wirehark, что клиент отправляет правильный формат пакета, но я чувствую, что то, как я читаю входящий/исходящий порт, неверно. Или это из-за того, как python отправляет данные? Можете ли вы дать несколько советов о том, где и почему я ошибаюсь? Заранее спасибо.


person m2r0007    schedule 18.08.2013    source источник
comment
Откуда struct ofp_connect? Значения in_port и out_port имеют длину 0 байтов (т.е. для них не выделяется место).   -  person lurker    schedule 19.08.2013
comment
Я удивлен, что это даже компилируется с двумя гибкими массивами. Это, конечно, нет в моей цепочке инструментов (Apple LLVM 4.2 C99).   -  person WhozCraig    schedule 19.08.2013
comment
Моя ошибка, я не вставил всю структуру, так как сосредоточился на полях in/out_port. Теперь его обновили.   -  person m2r0007    schedule 19.08.2013
comment
Ваше редактирование сделало вещи даже ценными. Теперь у вас есть 6 гибких массивов ...S-/   -  person alk    schedule 19.08.2013


Ответы (1)


Объявление struct ofp_connect нарушает следующий пункт стандарта ISO C:

6.7.2.1 Спецификаторы структуры и объединения ... 18 В качестве особого случая последний элемент структуры с более чем одним именованным членом может иметь тип неполного массива; это называется гибким членом массива.

Обратите внимание, что в вашем случае in_port и out_port должны были быть объявлены как in_port[] и out_port[], чтобы воспользоваться приведенным выше предложением, и в этом случае у вас будет два элемента гибкого массива, что запрещено приведенным выше предложением. Объявление массива нулевой длины является соглашением, принятым многими компиляторами (включая, например, gcc), которые имеют одинаковую семантику, но в вашем случае и in_port, и out_port разделяют одно и то же пространство (по сути, любые байты, следующие за структура ofp_connect). Более того, чтобы это работало, вы должны выделить некоторое пространство после структуры для гибких элементов массива. Поскольку, как вы сказали, struct connect является частью более крупной структуры, доступ к in_port возвращает «значение», хранящееся в члене содержащей структуры после connect sub-struct

person alexsh    schedule 19.08.2013
comment
Сейчас я обновил структуру. Это очищает так много вещей, что гибкие массивы используют одно и то же пространство, поэтому мне нужно выделить память. uint16_t * wportIN [] = (uint16_t) malloc (2); //где 2 = sizeof(uint16_t) это будет работать? - person m2r0007; 19.08.2013
comment
оператором uint16_t * wportIN = (uint16_t*)&cflow_mod-›connect.in_port; выделяет для него память. - person m2r0007; 19.08.2013
comment
Нет, это не сработает, к сожалению. Идея состоит в том, чтобы выделить последовательные (со структурой) байты. Итак, в вашем случае вам нужно сделать что-то вроде connect_var = malloc( sizeof(struct ofp_connect) + 2*sizeof(uint16_t) ). Вы также можете объявить как port_in, так и port_out как массивы размера 2 внутри ofp_connect (то есть, скажем, uint16_t port_in[2];). Оператор во втором комментарии заставляет компилятор резервировать память для указателя, но не выделяет (в куче) какую-либо память для самой структуры. - person alexsh; 19.08.2013
comment
И последнее замечание: создание структуры с гибким членом массива как части другой структуры приводит к неопределенному поведению в соответствии со стандартом, поэтому в вашем случае вы должны объявить размер port_in и port_out заранее, или полностью переосмыслите свой подход (возможно, используйте указатель на ofp_connect вместо того, чтобы включать его целиком). Вы по-прежнему можете иметь только один гибкий массив, другой должен иметь заранее определенный размер (т.е. известный во время компиляции). - person alexsh; 19.08.2013
comment
У меня проблема в том, что структуры являются частью спецификации, и ее не рекомендуется изменять. Более того, поскольку количество портов заранее неизвестно, имеет смысл иметь гибкий массив. По этим причинам мне нужно использовать эти гибкие массивы. - person m2r0007; 20.08.2013