【发布时间】:2011-12-18 22:22:39
【问题描述】:
问题
我正在努力通过网络将原始结构发送到另一端的已知程序,但不得不担心用于对齐结构的静默引入的内存(包括其他问题,如字节顺序)。我正在使用的是这样的:
typedef struct __attribute__((packed))
{
uint16_t field1;
uint16_t field2;
uint16_t field3;
} packed_1_s;
typedef struct __attribute__((packed))
{
uint16_t fieldA;
uint16_t fieldB;
packed_1_s structArray[10];
} packed_2_s;
typedef struct __attribute__((packed))
{
uint16_t fieldX;
packed_2_s fieldY;
uint8_t arrayZ[20];
} data_s;
我了解通常 packed_1_s 结构可以/应该为结构的每个实例分配额外的空间,以将其填充到编译器的首选大小(取决于为其构建的硬件),并且首选大小可以是任何地方从 2 个字节到 64 个字节(最近)。通常,如果我在 packed_2_s 中有一个 packed_1_s 实例,则不会有任何问题,但是当您尝试将元素放入数组时,我会理解存在一些差异。
尝试的解决方案
gcc 文档似乎表明,通过在 packed_2_s 定义中简单地包含 packed 属性,这些字段,即使它们是数组,都将尽可能紧密地打包,并且不会为 packed_2_s 结构添加空间对齐数组的元素。尽管有关 align() 属性的文档表明,数组的处理方式与其他字段不同,并且需要直接在字段上设置 align/packed 属性才能修改添加的额外间距以匹配指定的对齐方式(或缺少对齐方式)。我尝试在 structArray 字段上设置打包属性,当这不起作用时,通过在上面的代码中设置 arrayZ 上的打包属性进行测试:
packed_1_s structArray[10] __attribute__((packed));
uint8_t arrayZ[20] __attribute__((packed));
两次尝试都给了我一个编译器警告,提示在此上下文中不理解打包属性并将被跳过(我用“-Wall”构建的好东西)。
我希望解决这个问题的方法是使用属性 align(1),表示所需的 1 字节对齐方式与打包属性相当,但文档说 align() 属性只能 增加对齐和packed应该用于减少对齐。
注意事项
根据我从 GCC 文档中可以确定的情况,似乎有 3 种主要情况是插入了额外的内存。
- 结构内容可能有额外的内存分配给 结构本身以更改字段之间的间距。
有效地定义结构的内存映射 结构中的内容可能会改变(虽然不是顺序 元素)。- 结构可能有额外的内存分配给它们来填充 它们的整体尺寸更有效。这一般是 打算让其他变量在声明其中之一之后出现 它们的实例与 结构实例,其中“块”由系统/编译器定义。
- 数组,无论是否在结构内,都可能有额外的 添加到它们的内存以将元素转换为有效的对齐方式。
据我所知,packed 属性可用于影响结构并阻止在上述情况 1 和 2 中添加的额外内存,但似乎没有办法在我的情况下处理上述情况 3编译器。
问题
有什么方法可以保证 data_s 结构绝对没有额外的空间添加到它或它的任何子结构中,所以我在内存映射中没有编译器相关的变化?我是否误解了编译器可以插入空间来故意移动内存映射的情况?
编辑
我与当地的大师讨论了一些问题,听起来我对上面的案例 3 有一些误解。数组中的元素之间没有插入空格,但保证它们正确对齐的额外空间被添加到结构本身。显然,这表明诸如“sizeof(structureOnlyContaining_uint32_t)”之类的东西并不总是返回“4”,因为可能会添加额外的空间来对齐正在使用的编译器上的 uint32_t 数据类型。结果真的只有2种情况:
- 结构的内存映射中的字段之间的偏移量更大。
可以修改字段之间的空间以对齐每个字段。 这可以使用 packed 或 align() 属性进行更改。- 结构末端填充。结构的大小,由返回 sizeof(),可以修改,因此结构的数组最终 为系统正确对齐。这允许所有系统假设 结构的开头将始终对齐,从而导致问题 如果他们不是。这似乎不受 pack 或 align 属性的影响。
由于新的情况 2,结构中的数组元素不一定服从结构中指定的打包或 align() 属性,尽管数组的开头和紧随数组的字段会这样做。
然后我的问题是关于如何处理 packed_2_s 中的 structArray,因为整个数组的大小不能完全由 packed 属性来保证。有没有办法保证整个 structArray 字段的大小是固定的?应该注意的是,我不能过多地增加 packed_1_s 的大小,因为 data_s 结构需要保持尽可能小(它在流式传输场景中替换音频/视频数据)。
【问题讨论】:
-
你试过#pragma pack(1)
-
如果我没记错的话,我相信 #pragma pack() 大致相当于 pack 属性和 align() 属性组合成一个 pragma 调用。此外,如果您查看属性类型存在的原因,它们被有意定义为非编译指示选项,我想利用的原因(特别是如果不支持,它们会在编译时生成错误/警告)编译器)
-
诸如“sizeof(uint32_t)”之类的东西总是会返回他们总是为该平台返回的任何东西。 uint32_t 不是结构/联合,它是标量类型。
-
好吧,不好的例子。 sizeof(structureOnlyContaining_uint32_t) 可能是一个更好的例子。编辑了原件以反映更正。
-
不要使用压缩结构。编写适当的序列化函数。
标签: c arrays gcc attributes struct