2011-04-24 2 views
1

Я программирую в linux, что является новым для меня. Я работаю над проектом по разработке сетевого протокола уровня 7, и у нас есть эти пакеты, которые содержат ресурсы. И в зависимости от типа ресурса длина этого ресурса будет отличаться. Я как бы новичок в C/C++, и я не уверен, что хорошо понимаю профсоюзы. Идея заключалась в том, что я мог бы создать тип «общего ресурса», и в зависимости от того, какой ресурс я мог бы просто наложить void * в качестве указателя на эту структуру typedef, а затем вызвать содержащиеся в нем данные как угодно, он позаботится о «кастинге». В любом случае, вот что я придумал:(C/C++) Структуры, содержащие союзы, содержащие структуры ...?

typedef struct _pktresource 
{ 
    unsigned char Type; // The type of the resource. 

    union { 
     struct { // This is used for variable length data. 
      unsigned short Size; 
      void *Data; 
     }; 

     void *ResourceData; // Just a generic pointer to the data. 
     unsigned char Byte; 
     char SByte; 
     short Int16; 
     unsigned short UInt16; 
     int Int32; 
     unsigned int UInt32; 
     long long Int64; 
     unsigned long long UInt64; 
     float Float; 
     double Double; 
     unsigned int Time; 
    }; 
} pktresource, *ppktresource; 

Принципал, стоящий за этим, был прост. Но когда я делаю что-то вроде

pktresource.Size = XXXX 

Он начинается с 4 байтов в структуре вместо 1 байта. Неужели я не могу понять основную концепцию здесь? Потому что мне кажется.

EDIT: Забыл упомянуть, когда я ссылаться

pktresource.Type 

Он начинается с самого начала, как его предполагается.

EDIT: Исправление должно было добавлять утверждения прагмы для правильного выравнивания. После исправления, код выглядит следующим образом:

#pragma pack(push) 
#pragma pack(1) 

typedef struct _pktresource 
{ 
    unsigned char Type; // The type of the resource. 

    union { 
     struct { // This is used for variable length data. 
      unsigned short Size; 
      unsigned char Data[]; 
     }; 

     unsigned char ResourceData[]; // Just a generic pointer to the data. 
     unsigned char Byte; 
     char SByte; 
     short Int16; 
     unsigned short UInt16; 
     int Int32; 
     unsigned int UInt32; 
     long long Int64; 
     unsigned long long UInt64; 
     float Float; 
     double Double; 
     unsigned int Time; 
    }; 
} pktresource, *ppktresource; 

#pragma pack(pop) 
+3

«Я программирую в linux, что для меня ново.», «Я как бы новичок в C/C++», - и вы пишете сетевой протокол ???? –

+0

Я не новичок в создании сетей или в программировании или в самом Linux. Я программировал на окнах на одном или другом языке около 13 лет. Вы знаете ответ на мой вопрос, или вы просто сказали это по-настоящему? –

+0

«Я программировал окна на одном или другом языке уже около 13 лет» - и все же вы новичок в C/C++. На каких языках вы использовали? –

ответ

2

Am Я неисправный понять основную концепцию здесь?

Вам не хватает знания о structure alignment. По сути, он заставляет определенные поля выравниваться на> 1 байтовые границы в зависимости от их размера. Вы можете использовать #pragma, чтобы переопределить это поведение, но это может вызвать проблемы совместимости, если структура используется вне вашего приложения.

+0

oh man, haha ​​Я раньше слышал термин «выравнивание структуры», но не знал, что это было. Структура будет использоваться только внутри приложения для анализа сетевых данных, и ничего больше. –

+0

Тогда у вас не должно быть проблем. Что происходит, ваш член 'void * Data' (являющийся типом указателя) имеет длину 4 байта и, следовательно, выровнен на четырехбайтовой границе. Поскольку это самый большой член профсоюза, весь союз будет такого размера и выровнен на этой границе. Вот почему он начинается с байта 5 вместо байта 2. –

+0

Использование #pragma может замедлить работу, так как извлечение памяти будет иметь дело с разделом данных по границам слов. Если космос не рассматривается, я не думаю, что я бы вошел в компоновку компоновщика по умолчанию. (Вы также можете переместить Тип в нижнюю часть структуры!) –

2

Я думаю, проблема в выравнивании. По умолчанию большинство компиляторов соответствуют размеру слова машины/ОС, в этом случае 32 бита/4 байта. Итак, поскольку у вас есть это поле unsigned char Type спереди, компилятор нажимает поле «Размер» на следующую четную границу по 4 байта.

попробовать

#pragma pack 1 

впереди вас определения структуры.

Я не знаю, какой компилятор вы используете, но это хороший старомодный код на C, который регулярно используется для сетевого программирования, так как до этого были рождены большинство этих грубых детей на StackOverflow.

+0

Я использую gcc 4.4.3 –

+0

Насколько я понимаю, прочитав статью в вики, большое спасибо, я бы 1-го уровня, но у меня нет достаточной репутации, я думаю. –

Смежные вопросы