c-关于结构中的内存对齐和sizeof运算符的可移植性的问题



我有一个关于C语言中结构的结构填充和内存对齐优化的问题。我通过网络发送一个结构,我知道,出于运行时优化的目的,结构中的内存是不连续的。我在本地计算机上运行了一些测试,事实上,sizeof(my_structure)与我所有结构成员的总和不同。我做了一些研究,找出了两件事:

  • 首先,sizeof()运算符检索结构的填充大小(即存储在内存中的实际大小)。

  • 当在结构声明中指定__属性__((___packed___)时,编译器将禁用此优化,因此sizeof(my_structure)将与我的结构的字段之和完全相同。

话虽如此,我想知道sizeof运算符是否在每个编译器实现和每个体系结构上都得到了填充大小,换句话说,用memcpy复制结构是否总是安全的,例如使用sizeof运算符,如:

memcpy(struct_dest, struct_src, sizeof(struct_src)); 

我还想知道__属性__((__打包__))的真正目的是什么,它是用来在提交结构时在网络上发送不太重要的数据量,还是实际上用来避免一些未指明的、依赖于平台的sizeof操作员行为?

提前谢谢。

不同体系结构上的不同编译器可以而且确实使用不同的填充。因此,对于有线传输来说,打包结构以实现一致的二进制布局并不罕见。这样就可以满足在不同体系结构上运行的每一端的代码。

但是,如果使用这种方法,还需要确保数据类型大小相同。例如,在64位系统上,long在Windows上为4字节,在其他地方几乎为8字节。您还需要处理端序问题。标准是按照网络字节顺序通过导线进行传输。在实践中,您最好使用专用的序列化库,而不是试图重新设计所有这些问题的解决方案。

我正在通过网络发送结构

停在那里。也许有些人会不同意我的观点(在实践中,你确实看到很多项目这样做),但struct是一种在内存中布局的方式——它不是一种序列化机制。通过在工作中使用这个工具,你已经把自己束缚在一堆不可移植的假设中了。

当然,你可以用结构填充杂注和属性之类的东西来伪造它,但你真的能吗?即使有那些不可移植的机制,你也永远不知道会出现什么怪癖。我记得我在一个使用"打包"结构的代码库中工作,然后突然把它带到一个访问必须与单词对齐的平台上。。。尽管它名义上是同一个编译器(因此支持相同的专有扩展),但它产生的二进制文件崩溃了。你从这条路上得到的任何痛苦都可能是应得的,我想说,只有当你能100%确定它只在给定的编译器和环境中运行时,你才能接受它,而且这永远不会改变。我认为更安全的选择是编写一个适当的序列化机制,不允许跨流程边界编写结构。

使用memcpy复制结构是否总是安全的,例如使用sizeof运算符

是的,这就是提供sizeof操作员的目的。

通常使用__attribute__((__packed__))不是为了考虑尺寸,而是为了确保结构的布局与您想要的完全一样。

例如:如果一个结构要用于匹配硬件或通过导线发送,那么它需要具有完全相同的布局,没有任何填充。这是因为不同的体系结构通常实现不同的种类&填充和对齐的数量,确保共同点的唯一方法是通过使用填充将填充从图片中删除。

最新更新