Двойственность упаковки структуры

Я пишу код для 4_r13.pdf" rel="nofollow">спецификации, которая определяет структуры без упаковки, Например:

struct LASHeader_1p2
{
    char FileSig[4]; //= "LASF";                    // 4
    unsigned __int16 FileSource;                    // 2   6
    unsigned __int16 Reserved_Unused;               // 2   8
    unsigned __int32 Project_ID_Data1;              // 4  12
    unsigned __int16 Project_ID_Data2;              // 2  14
    unsigned __int16 Project_ID_Data3;              // 2  16
    char Project_ID_Data4[8];                       // 8  24
    unsigned char Version_Major;                    // 1  25
    unsigned char Version_Minor;                    // 1  26
    char System_ID[32];                             //32  58
    char Software[32];                              //32  90
    unsigned __int16 FC_Day, FC_Year, Header_Size;  // 2,2,2 96
    unsigned __int32 Offset_to_Data;                // 4 100 0x60
    unsigned __int32 VarLenRecs;                    // 4 104 0x64
    unsigned char Pt_DataFormat;                    // 1 105 0x65
    unsigned __int16 Pt_DataRecLen;                 // 2 107 0x68
    unsigned __int32 PointCount;                    // 4 111 0x6A
    unsigned __int32 Point_by_Return_0;             // 4 115
    unsigned __int32 Point_by_Return_1;             // 4 119
    unsigned __int32 Point_by_Return_2;             // 4 123
    unsigned __int32 Point_by_Return_3;             // 4 127
    unsigned __int32 Point_by_Return_4;             // 4 131
    double Xscale;                                  // 8 139
    double Yscale;                                  // 8 147
    double Zscale;                                  // 8 155
    double Xoffset;                                 // 8 163
    double Yoffset;                                 // 8 171
    double Zoffset;                                 // 8 179
    double MaxX;                                    // 8 187
    double MinX;                                    // 8 195
    double MaxY;                                    // 8 203
    double MinY;                                    // 8 211
    double MaxZ;                                    // 8 219
    double MinZ;                                    // 8 227
};

Около unsigned char Pt_DataFormat; структура выходит за пределы выравнивания по умолчанию (4 байта). Чтобы компенсировать это, я использую параметр компилятора /Zp1 для использования структуры без заполнения/выравнивания. Хотя потенциально медленнее, это позволяет мне читать байты и интерпретировать как структуру:

char* buffer = (char*)malloc(sizeof(LASHeader_1p2));
pReadStream.read(buffer ,sizeof(LASHeader_1p2));
LASHeader_1p2* Header = (LASHeader_1p2*)buffer;

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

Однако другим библиотекам не нравится /Zp1, я подозреваю, что они содержат внутренние дополненные структуры, которые больше не работают, когда они не заполнены.

Я просматривал pragma pack и __declspec(align()), но я не уверен, что подойдет и как их использовать.

Может ли кто-нибудь пролить свет на то, как действовать, чтобы читать и отображать структуру без заполнения, но поддерживать дополнение для других библиотек, которые этого требуют?


person Michael Stimson    schedule 20.02.2015    source источник
comment
Зависит от того, какой компилятор вы используете, но, как правило, все они предоставляют способ передать текущее значение упаковки, изменить его для некоторого количества кода, а затем вернуться к тому, что было раньше.   -  person Retired Ninja    schedule 20.02.2015
comment
Я использую визуальную студию 2010, С++. Идет ли #pragma в заголовок с объявлением структуры или вокруг кода, который ее использует? что мне использовать, когда я закончу этот бит и хочу, чтобы он вернулся к умолчанию?   -  person Michael Stimson    schedule 20.02.2015


Ответы (1)


Для Visual Studio вы хотели бы окружить свою структуру следующим образом:

#pragma pack(push, 1) //Save packing value and set to 1 byte
<struct definition>
#pragma pack(pop)  //Reset to whatever the packing was before.

Итак, это:

#include <iostream>

#pragma pack(push, 1)
struct packed
{
    char FileSig[4]; //= "LASF";                    // 4
    unsigned __int16 FileSource;                    // 2   6
    unsigned __int16 Reserved_Unused;               // 2   8
    unsigned __int32 Project_ID_Data1;              // 4  12
    unsigned __int16 Project_ID_Data2;              // 2  14
    unsigned __int16 Project_ID_Data3;              // 2  16
    char Project_ID_Data4[8];                       // 8  24
    unsigned char Version_Major;                    // 1  25
    unsigned char Version_Minor;                    // 1  26
    char System_ID[32];                             //32  58
    char Software[32];                              //32  90
    unsigned __int16 FC_Day, FC_Year, Header_Size;  // 2,2,2 96
    unsigned __int32 Offset_to_Data;                // 4 100 0x60
    unsigned __int32 VarLenRecs;                    // 4 104 0x64
    unsigned char Pt_DataFormat;                    // 1 105 0x65
    unsigned __int16 Pt_DataRecLen;                 // 2 107 0x68
    unsigned __int32 PointCount;                    // 4 111 0x6A
    unsigned __int32 Point_by_Return_0;             // 4 115
    unsigned __int32 Point_by_Return_1;             // 4 119
    unsigned __int32 Point_by_Return_2;             // 4 123
    unsigned __int32 Point_by_Return_3;             // 4 127
    unsigned __int32 Point_by_Return_4;             // 4 131
    double Xscale;                                  // 8 139
    double Yscale;                                  // 8 147
    double Zscale;                                  // 8 155
    double Xoffset;                                 // 8 163
    double Yoffset;                                 // 8 171
    double Zoffset;                                 // 8 179
    double MaxX;                                    // 8 187
    double MinX;                                    // 8 195
    double MaxY;                                    // 8 203
    double MinY;                                    // 8 211
    double MaxZ;                                    // 8 219
    double MinZ;                                    // 8 227
};
#pragma pack(pop)

struct unpacked
{
    char FileSig[4]; //= "LASF";                    // 4
    unsigned __int16 FileSource;                    // 2   6
    unsigned __int16 Reserved_Unused;               // 2   8
    unsigned __int32 Project_ID_Data1;              // 4  12
    unsigned __int16 Project_ID_Data2;              // 2  14
    unsigned __int16 Project_ID_Data3;              // 2  16
    char Project_ID_Data4[8];                       // 8  24
    unsigned char Version_Major;                    // 1  25
    unsigned char Version_Minor;                    // 1  26
    char System_ID[32];                             //32  58
    char Software[32];                              //32  90
    unsigned __int16 FC_Day, FC_Year, Header_Size;  // 2,2,2 96
    unsigned __int32 Offset_to_Data;                // 4 100 0x60
    unsigned __int32 VarLenRecs;                    // 4 104 0x64
    unsigned char Pt_DataFormat;                    // 1 105 0x65
    unsigned __int16 Pt_DataRecLen;                 // 2 107 0x68
    unsigned __int32 PointCount;                    // 4 111 0x6A
    unsigned __int32 Point_by_Return_0;             // 4 115
    unsigned __int32 Point_by_Return_1;             // 4 119
    unsigned __int32 Point_by_Return_2;             // 4 123
    unsigned __int32 Point_by_Return_3;             // 4 127
    unsigned __int32 Point_by_Return_4;             // 4 131
    double Xscale;                                  // 8 139
    double Yscale;                                  // 8 147
    double Zscale;                                  // 8 155
    double Xoffset;                                 // 8 163
    double Yoffset;                                 // 8 171
    double Zoffset;                                 // 8 179
    double MaxX;                                    // 8 187
    double MinX;                                    // 8 195
    double MaxY;                                    // 8 203
    double MinY;                                    // 8 211
    double MaxZ;                                    // 8 219
    double MinZ;                                    // 8 227
};


int main()
{
    std::cout << "sizeof(packed)   = " << sizeof(packed) << "\n";
    std::cout << "sizeof(unpacked) = " << sizeof(unpacked) << "\n";
    return 0;
}    

выходы

sizeof(packed)   = 227
sizeof(unpacked) = 232

Вы даже можете вкладывать их друг в друга и давать разные имена уровням, если хотите, но мне редко приходилось это делать. Документация: здесь.

person Retired Ninja    schedule 20.02.2015
comment
Спасибо, я был почти уверен, что у меня есть правильный инструмент, просто не знал, где его применить, и это хорошо прояснило для меня. Теперь я могу использовать пакет #pragma в заголовке, содержащем структуру, и компилировать в упаковку структуры по умолчанию, что позволяет внешней библиотеке работать правильно, а также правильно динамически приводить структуру. - person Michael Stimson; 23.02.2015