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

时间:2012-04-01 07:45:08

标签: c memory-management sizeof

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

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

  • 在宣言中指定 __ 属性 __ (( __ 打包 __ )时编译器禁用此优化的结构,因此sizeof(my_structure)将与我的结构字段的总和完全相同。

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

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

我也想知道 __ 属性的真正目的是什么 __ (( __ 打包 __ ) ),用于在提交结构时发送网络上数据不太重要的数量,或者它实际上用于避免某些未指定的和平台相关的sizeof运营商行为?

先谢谢。

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

我通过网络发送结构

停在那里。也许有些人会不同意我的意见(实际上你确实看到很多项目正在这样做),但是struct是一种在内存中布局的方式 - 它不是一个序列化机制。通过使用此工具完成工作,您已经将自己与一系列不可移植的假设联系在一起。

当然,你可以用结构填充编曲和属性来伪装它,但是 - 你真的可以吗?即使使用那些非便携式机制,您也不会知道可能出现的怪癖。我记得在一个代码库中工作,其中"打包"使用了结构,然后突然把它带到一个平台,在那里访问必须是单词对齐的...即使它名义上是相同的编译器(因此支持相同的专有扩展)它产生了崩溃的二进制文件。你从这条路上得到的任何痛苦都可能是值得的,我只想说,如果你能100%确定它只会在给定的编译器和环境中运行,那就永远不会改变。我说更安全的做法是编写一个不允许在跨进程边界编写结构的正确序列化机制。

答案 2 :(得分:1)

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

是的,这是提供sizeof运营商的目的。

通常__attribute__((__packed__))不是用于尺寸考虑因素,而是当您想要确保结构的布局完全符合您的要求时。

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