C++ #pragma pack的奇怪行为
我在使用C++ #pragma pack的奇怪行为,c++,gcc,struct,pragma,gcc4.4,C++,Gcc,Struct,Pragma,Gcc4.4,我在使用#pragma pack时遇到了一个奇怪的问题 我有以下结构: st_a:用#pragma pack(1)包装。大小=1字节。包含位字段 st#u b:用#pragma pack(2)包装。大小=14字节 st#u c:包装有#pragma包装(2)。大小=16字节。包含st_a和st_b st\u d:用#pragma pack(2)包装。大小=16字节。包含st_a和st_b的内容(st_b的成员) 因此,由于st#u a是在#pragma pack(1)下压缩的1字节,并且由于它在
#pragma pack
时遇到了一个奇怪的问题
我有以下结构:
st_a
:用#pragma pack(1)
包装。大小=1字节。包含位字段st#u b
:用#pragma pack(2)
包装。大小=14字节st#u c
:包装有#pragma包装(2)
。大小=16字节。包含st_a
和st_b
st\u d
:用#pragma pack(2)
包装。大小=16字节。包含st_a
和st_b
的内容(st_b
的成员)st#u a
是在#pragma pack(1)
下压缩的1字节,并且由于它在st#u c
内,而st#u c是在下压缩的,在st_a
之后的st_c
中应该有一个额外的填充字节,该额外字节后面应该是st_b
的内容,这是一个偶数长度的字符缓冲区(10)
但是,当我把st_b
的内容拿出来直接放进st_a
时,这件事就很奇怪了。填充显示在字符缓冲区之后,而不是之前(请参见下面的输出)
有人能解释为什么会发生这种奇怪的行为吗
代码:
注意:我使用的是GCC版本4.4.x
关于输出的一些注意事项:
在第一行中,5b
是在4
之间引入的填充字节,它是1字节st_a
和41
之间,后者是st_b
的缓冲区的第一个字符
在第二行中,0
是在缓冲区的最后一个字符4a
和a
之间引入的填充字节,后者是st\u d
中字符缓冲区后面的整数
第三行打印所有结构的大小。您没有正确检测到填充。您是否希望填充为零字节?没有理由期望这样。填充字节中的值可以是任何值。
您在末尾看到的零是st_b.x1
的4个字节的一部分。它的值是10,作为一个小的endian 2的补码整数,可以存储为0A 00 00
04 5b 41 42 43 44 45 46 47 48 49 4a 0a 00 00 00
^ ^ ^-----------------------------^---------^
| | st_b.buf st_b.x1
| random padding byte
|
st_a
查看填充的更好方法是使用offsetof
宏。例如:
#include <stdio.h>
#include <stddef.h>
#pragma pack(push)
#pragma pack(1)
struct Pack1 {
char x;
};
#pragma pack(2)
struct Pack2 {
short y;
};
struct Combined {
struct Pack1 p1;
struct Pack2 p2;
};
#pragma(pop)
int main()
{
printf("offset of p1: %u, offset of p2: %u\n",
offsetof(struct Combined, p1),
offsetof(struct Combined, p2));
return 0;
}
这清楚地表明在p1
和p2
之间有一个填充字节
将填充视为零的另一种方法是在结构声明之后立即将其所有字节归零:
st_c one;
memcpy(&one, 0, sizeof(st_c);
然后,程序的输出将如下所示:
04 00 41 42 43 44 45 46 47 48 49 4a 0a 00 00 00
当询问编译器扩展时,您应该告诉我们您使用的编译器。@eerorika,我已经更新了我的问题@雷蒙陈,我同意你的看法!你能澄清我的另一个疑问吗?如果st_c
中的缓冲区大小是奇数长度怎么办?在st_d
后面的st_a
中不需要填充,因为下一个字段是可以字节对齐的无符号字符。在st_a
之后的st_c
中需要填充,因为下一个字段是标记为需要2字节对齐的st_b
。想象一下,如果有一个新的结构st_e
,它与st_c
相同,但具有4字节对齐。你不能指望st_d
猜测buf1
和x1
是内联st_c
还是内联st_e
。然后st_b
将是(比如)9字节buf
,一个填充字节,然后是int
。我知道5b
是填充字节。问题有所不同,请仔细阅读问题。不过,感谢您的努力:-)。我确实学到了一些新东西:偏移量
!是的,我现在明白了。如果你把问题简化到最基本的问题上,那就更清楚了。在您的示例中,有很多额外的代码是不相关的,比如st_a
中的位字段和st_b
中的int。我认为陈雷蒙的评论回答了你的问题。
offset of p1: 0, offset of p2: 2
st_c one;
memcpy(&one, 0, sizeof(st_c);
04 00 41 42 43 44 45 46 47 48 49 4a 0a 00 00 00