когда указатель приведения указывает на структуру, содержащую объединение

У меня проблема со структурой, содержащей объединение. Вот проблема:

typedef struct
{
    unsigned char Type;                          
    union
    {
        unsigned char Length;
        unsigned __int16 Length2;
    }
    char Value[0];    
} TLV_TUPLE, *PTLV_TUPLE;

Если Type == 0x40h, я использую Length2, иначе использую Length.

Я использую эту структуру для чтения этого файлового потока (в шестнадцатеричном формате):

FE 01 01 40 12 00 30 …

Теперь код:

unsigned char * m_pTLV;

/*code here to  let m_pTLV points to the
  first byte of the file, that is, point to 'FE' */

PTLV_TUPLE pTlv = (PTLV_TUPLE)m_pTLV; // cast m_pTLV to PTLV_TUPLE

Затем, когда я проверяю значение pTlv с помощью отладчика, я вижу это:

pTlv->Type == FE
pTlv->Length == 1
pTlv->Length2 == 4001
pTlv->Value == 12

Разве Length2 не должно быть 0x101, а value не должно быть 48?

машина с прямым порядком байтов.

Пожалуйста, помогите мне с этим...


person karatelambda    schedule 06.03.2011    source источник
comment
Чтение struct непосредственно из файла почти всегда плохая идея. Напишите (а еще лучше сгенерируйте) свой рабочий код сериализации член за членом.   -  person 6502    schedule 06.03.2011
comment
@ 6502, вы, вероятно, правы для данных, которые нужно будет использовать в другом месте, но для данных, которые когда-либо будут использоваться только в этой единственной программе, предпочтительнее однократное чтение/запись (IMNSHO), чем все усилия, затраченные на сериализацию отдельных элементы. Файл данных может потребовать миграции, если заполнение или другие форматы когда-либо изменятся, но я бы предпочел потратить эти усилия, когда/если это необходимо.   -  person paxdiablo    schedule 07.03.2011


Ответы (1)


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

01, следующий за FE, является дополнением, фактическое объединение начинается со следующего байта. Это связано с тем, что на требования выравнивания объединения влияют требования выравнивания его частей.

Поскольку Length2 требует выравнивания по двухбайтовой границе, перед ним вставляется байт заполнения, чтобы гарантировать, что это произойдет.

Если бы поток, в котором вы читали, был FE FF 01 40 12 00 30 ..., вы все равно получили бы те же значения.


Кроме того, я думаю, что "Shouldn’t Length2 be 0101 and value be 48?" на самом деле должно было читать 64 (0x40), а не 48 (0x30). Я предполагаю, что это была опечатка с вашей стороны.


Если вам нужно, чтобы в структуре не было отступов, не существует стандартного способа сделать это, но ваш компилятор должен предоставить такой способ. Например, вы можете использовать что-то вроде атрибутов в gcc:

typedef  struct {
    unsigned char Type;                          
    union {
        unsigned char Length;
        unsigned __int16 Length2;
    }
    char Value[0];    
} __attribute__ ((aligned(1),packed)) TLV_TUPLE;

Другие среды могут предоставить #pragma pack или что-то подобное для достижения той же цели.

person paxdiablo    schedule 06.03.2011