C struct 打包有啥保证吗?

Posted

技术标签:

【中文标题】C struct 打包有啥保证吗?【英文标题】:Are there any guarantees about C struct packing?C struct 打包有什么保证吗? 【发布时间】:2018-05-19 15:44:02 【问题描述】:

是否有任何保证在 C 中打包结构?

举个例子,假设sizeof(double) == 8,是否保证sizeof(struct double x, y; ) == 16

我知道这个问题背后的意图与严格的别名规则相冲突,因此假设严格别名被禁用,例如在 gcc 的情况下使用-fno-strict-aliasing

为了避免任何进一步的猜测:目的是了解结构与其显式打包的对应物的兼容性。请注意,即使在以下情况下,别名也是相关的:Are C-structs with the same members types guaranteed to have the same layout in memory? 。不用担心我想访问单个字节。

【问题讨论】:

您的问题不包含任何别名。我害怕看到你打算如何添加它,因为你提出来了。 我知道的唯一保证是第一个成员之前没有填充。如果只有 1 个成员,则应该没有填充,所以 sizeof(struct double x[2]; ) == 2 * sizeof(double) 应该保持。 @StoryTeller 我怀疑他计划通过一些别名方法访问结构的字节,如果他知道如何打包的话。 这是XY problem? @mch 我不确定你的第二点是否成立。考虑到指向不同数据类型的指针可以有不同的大小和对齐限制,但所有指向结构和联合类型的指针都具有相同的大小和对齐要求。因此,例如char * 可能比struct char * 大,在这种情况下,结构可能需要比_Alignof(char) 更大的对齐。 【参考方案1】:

C 标准关于结构打包的唯一说明是struct 的开头可能不存在填充。它不保证字段之间或末尾的填充。

C standard 的第 6.7.2.1 节对结构进行了如下说明:

15 在结构对象中,非位域成员和位域所在的单元的地址在 声明它们的顺序。指向结构对象的指针, 适当转换,指向其初始成员(或者如果该成员是 一个位域,然后到它所在的单元),反之亦然。 结构对象中可能有未命名的填充,但不是 开始。

...

17 结构或联合的末尾可能有未命名的填充。

话虽如此,大多数实现往往与结构的打包方式相当一致。非结构变量n 字节大小(或数组这样的变量)将倾向于从n 字节边界开始。结构中的结构将倾向于根据其子字段的对齐方式进行对齐。

The Lost Art of C Structure Packing 对此进行了更详细的介绍。

【讨论】:

除此之外,还有一种有趣的序列化方法,称为 Cap'n Proto,旨在使结构打包在不同的机器、操作系统等之间得到控制和一致。消息(结构)内容由一个模式并由 Cap'n Proto 的工具和库实现,序列化被简化为处理字节顺序,它为你做了:所以它非常非常快。有很多值得推荐的地方。

以上是关于C struct 打包有啥保证吗?的主要内容,如果未能解决你的问题,请参考以下文章

UDP python to c - 打包二进制数据 - struct.pack('<ff',

qt中如何解包利用python 的struct.pack()函数打包的数据

使用python中的struct模块打包和解包可变长度数组/字符串

C# Struct 到字节数组的编组方式与 Delphi 中的打包记录相同

.net 项目在Debug模式下打包跟在release模式下打包有啥区别?

将字节串解读为打包的二进制数据