我有一个映射到字节数组的结构。但我发现似乎并非所有字段都已正确映射。我想知道这是一个对齐问题还是一个错误。
struct _sg64_struct
{
SG64_PCSC_TLV_HEADER header; /* This is 2 bytes */
gint8 id_perso;
gint8 status;
gint8 fare_type;
gint16 fare_zone;
gint8 support_type;
gchar loginPerso[15];
};
我将此结构映射到此字节:
41150002000000000E2020202020202020202020202020
但我发现support_type得到0x0E值而不是00应该是。如果我们映射它
struct _sg64_struct
{
SG64_PCSC_TLV_HEADER header; 4115
gint8 id_perso; 00
gint8 status; 02
gint8 fare_type; 00
gint16 fare_zone; 0000
gint8 support_type; 00
gchar loginPerso[15]; E2020202020202020202020202020
};
但是当我用0E说support_type时,我得到了。奇怪的是,如果我将fare_zone映射为两个字节就可以了。
struct _sg64_struct
{
SG64_PCSC_TLV_HEADER header; /* This is 2 bytes */
gint8 id_perso;
gint8 status;
gint8 fare_type;
gint8 fare_zone[2];
gint8 support_type;
gchar loginPerso[15];
};
这种结构有效。但问题是为什么?我们可以信任编译器类型吗?
答案 0 :(得分:3)
它不起作用,因为结构内部有填充物。这是一个非常糟糕的做法。假设结构成员的偏移量只是所有先前成员的总和。尺寸错了。
答案 1 :(得分:2)
结构中每个成员的类型通常具有默认对齐,这意味着除非程序员另有要求,否则它将在预定边界上对齐。
gint8
typedef signed char gint8;
在所有平台上保证为8位的有符号整数。
和
gint16
typedef签名短gint16;
所有平台上的无符号整数保证为8位。
如果您的结构中有gint16
类型fare_zone
,则编译器会将struct _sg64_struct
填充为1个字节,以对齐fare_zone
。< / p>
因此,当fare_zone
类型为gint16
时,您的结构会发生这种情况:
struct _sg64_struct
{
SG64_PCSC_TLV_HEADER header; // 2 bytes 4115
gint8 id_perso; // 1 byte 00
gint8 status; // 1 byte 02
gint8 fare_type; // 1 byte 00
gchar pad[1]; <------ // 1 byte 00 (compiler is padding 1 byte to align fare_zone, as short type are 2-byte aligned)
gint16 fare_zone; // 2 byte 0000
gint8 support_type; // 1 byte 0E
gchar loginPerso[15]; // 15 byte 2020202020202020202020202020
};
这就是support_type
得到0x0E值而不是00的原因。
当您的结构中有gint8
类型的fare_zone
时,编译器的填充大小为struct _sg64_struct
,其中1个字节为对齐边界并执行尾部填充
struct _sg64_struct
{
SG64_PCSC_TLV_HEADER header; // 2bytes 4115
gint8 id_perso; // 1 byte 00
gint8 status; // 1 byte 02
gint8 fare_type; // 1 byte 00
gint8 fare_zone[2]; // 2 byte 0000 (no alignment required as the char types are 1 byte aligned)
gint8 support_type; // 1 byte 00
gchar loginPerso[15]; // 15 byte 0E2020202020202020202020202020
gchar pad[1]; <------ // Compiler is padding 1 byte to alignment boundary of structure
};
这就是这种结构有效的原因。
我建议不要使用字节序列映射结构,因为结构成员的对齐可能会因编译器和底层平台而异。
附加说明:
每个现代编译器都会根据体系结构自动使用数据结构填充。有些编译器甚至支持警告标志-Wpadded
,它会生成有关结构填充的有用警告。这些警告有助于程序员在需要更高效的数据结构布局时进行手动维护。
<强> -Wpadded 强>
如果填充包含在结构中,则发出警告,要么对齐元素 结构或对齐整个结构。有时这个 发生可以重新排列结构的字段 减少填充,使结构更小。
因此,如果您的编译器支持警告标志-Wpadded
,请尝试使用它编译代码。这将帮助您理解编译器包含在结构中的填充。