我想获取一些 C 结构中的部分数据以对它们进行部分序列化/反序列化,将字节从内存写入磁盘,反之亦然。
这些结构是事先不知道的,它们是用我自己的 C 代码生成器(以及将其序列化的代码)动态构建的。可序列化字段将放置在结构的开头。
假设一个结构有 4 个字段,前两个要序列化:
typedef struct {
int8_t x1;
int32_t x2; /* 1 + 4 = 5 bytes (if packed) */
int8_t y1;
int32_t y2; /* 1 + 4 +1 + 4 = 10 bytes (if packed) */
} st;
我计划获取指向结构变量的指针并写入/读取覆盖前两个字段 (x1, x2
) 的 n
字节。我认为我不需要担心对齐/打包,因为我不打算让序列化在不同的编译中幸存下来(只有一个唯一的可执行文件才能读取/写入数据)。而且,由于我的目标是广泛的编译器架构,所以我不想对对齐打包或编译器特定技巧进行假设。
然后,我需要计算字节数。由于对齐填充,我不能只执行 sizeof(st.x1)+sizeof(st.x2)
。所以,我打算减去指针,从结构的开始到第一个“非持久”字段:
st myst;
int partsize = (char*)&myst.y1 - (char*)(&myst);
printf("partial size=%d (total size=%d)\n",partsize,sizeof(myst));
这似乎可行。并且可以放在宏中。
(作为记录:我还尝试编写另一个不需要结构实例的宏,例如 this ,但在这里似乎不可能 - 但这对我来说并不重要)。
我的问题:这是否正确且安全?您能看出任何潜在的陷阱或更好的方法吗?
除其他事项外:C 标准(和实际编译器)是否假定结构字段在内存中的顺序与它们在源代码中定义的顺序相同?这可能是一个愚蠢的问题,但我想确定...
更新:从答案和我自己的发现中得出的一些结论:
我的做法好像没有问题。特别是,C 规定结构字段永远不会更改顺序。
也可以(如 aswer 所建议的那样)从最后一个持久字段开始计数并添加其大小:
(char*)&myst.x2 + sizeof(&myst.x2) - (char*)( &myst)
。这将是等效的,除了它不包括最后一个字段的填充字节(如果存在)。一个非常小的优势 - 也是一个非常小的劣势,在于不那么简单。但是带有
offsetof
的公认答案似乎比我的建议更可取。它是清晰表达和纯编译时的,它不需要结构的实例。它似乎是标准的,可用于任何编译器。 如果不需要编译时构造,并且有可用的结构实例(如我的情况),两种解决方案在本质上是等价的。
最佳答案
您是否查看过offsetof
工具?它返回成员从结构开始的偏移量。所以 offsetof (st, x2)
返回 x2
从结构开始的偏移量。因此,在您的示例中,offsetof (st, x2) + sizeof(st.x2)
将为您提供序列化组件的字节数。
这与您现在所做的非常相似,您只需忽略 x2 之后的填充并使用很少使用的 C。
关于c - C 结构的 sizeof() 部分 - 有点像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4879363/