结构包装两面性

时间:2015-02-20 05:21:08

标签: c++ structure memory-alignment preprocessor-directive compiler-options

我正在编写代码a specification,它定义了没有打包的结构,例如:

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()),但不确定哪种方法适合以及如何使用它们。

任何人都可以了解如何继续,阅读和转换结构而不填充,但保留其他需要它的库的填充?

1 个答案:

答案 0 :(得分: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

如果你愿意,你甚至可以嵌套它们并给出不同级别的名字,但我很少这么做。文档为here