【发布时间】:2023-01-18 00:59:36
【问题描述】:
因此,我正在编写一个将用于反序列化二进制数据流的结构。为了说明这一点,这里有一个精简版:
typedef struct
{
bool flag1 : 1;
bool flag2 : 1;
bool flag3 : 1;
bool flag4 : 1;
uint32_t reserved : 28;
} frame_flags_t;
typedef struct
{
/* Every frame starts with a magic value. */
uint32_t magic;
frame_flags_t flags;
uint8_t reserved_1;
/* A bunch of other things */
uint32_t crc;
} frame_t;
我的问题是,如果执行以下操作:
frame_t f;
memcpy(&f, raw_data_p, sizeof(frame_t));
我能保证 f.flags.flag1 真的是第一位(在 magic 成员之后,假设是一个整齐打包的结构(它是))?而那个.flags2 将是紧随其后的那个,等等?
据我了解,C 和 C++ 标准并不能保证这一点。海湾合作委员会吗?
【问题讨论】:
-
显然这是未指定的行为。即使 GCC 不填充这个结构,我也不会使用它...... en.cppreference.com/w/c/language/bit_field
-
您在那里有多个问题:1)位域具有实现定义的行为。它们不需要以您可能期望的方式放置。而且您似乎假设该结构为 32 位大。当使用不同的类型时,你不应该依赖它。 2) 你的结构
frame_t可能包含一些填充字节。 3)你的机器的字节序不需要匹配你流中数据的字节序。 -
我相信,如果您将自己限制在小端架构(或大端架构,如果您能找到的话),您将获得一致的结果。我也相信使用原始结构进行反序列化是一个糟糕的主意,但这是一种非常流行的技术,所以不要让我阻止你。 :-)
-
使用位域,甚至是普通结构来进行序列化并不是一个好主意。但是既然你问了,this GCC manual page 说基本上是“由 ABI 决定。”.
-
@user694733 你有什么建议而不是反序列化?一次 memcpying 每个成员? (并使用
.flag1 = rawmemory & bitmask;作为位域)?
标签: c gcc bit-fields