((包装))结构嵌套阵列上__attribute __的影响? [英] Effects of __attribute__((packed)) on nested array of structures?

查看:172
本文介绍了((包装))结构嵌套阵列上__attribute __的影响?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我工作的另一边通过网络发送的原始结构,以一个已知的计划,但担心用于对准结构(如字节序等问题都包括在内)的默默推出内存。什么我工作是一样的东西:

  typedef结构__attribute __((包装))
{
   uint16_t FIELD1;
   uint16_t域2;
   uint16_t FIELD3;
} packed_1_s;typedef结构__attribute __((包装))
{
   uint16_t FIELDA;
   uint16_t fieldB;
   packed_1_s structArray [10];
} packed_2_s;typedef结构__attribute __((包装))
{
   uint16_t fieldX;
   packed_2_s fieldY;
   uint8_t有arrayZ [20];
} data_s;

据我了解,一般情况下,packed_1_s结构可以/将有分配结构的每个实例额外的空间来填补它的编译器的青睐大小(取决于它被建为硬件),而青睐大小可以在任何地方从2个字节到64字节(最近)。通常情况下,如果我有packed_1_s在packed_2_s一个实例就没有问题,但我给予理解有一些差异,当你试图把数组中的元素。

试图解决方案

GCC的文档似乎表明,通过简单地包括在packed_2_s定义,字段packed属性,即使他们的阵列,都将被作为紧凑越好,到packed_2_s结构,不会增加空间对齐阵列的元件。 )上对齐(该文档的属性,虽然表明阵列比其他领域的处理方式不同,需要的对齐/ packed属性的字段设置直接对其进行修改多余行距添加到指定的对齐匹配(或缺乏)。我试着设置上都structArray场packed属性,当没有工作,通过设置arrayZ packed属性在code上面做了一个试验:
   

  packed_1_s structArray [10] __attribute __((包装));uint8_t有arrayZ [20] __attribute __((包装));

这两种尝试给了我一个编译器警告packed属性并没有在这方面的理解和将被跳过(还好我构建-Wall)。

我希望的方式来解决这个问题是使用属性调整(1),表明这与packed属性1字节的所需的对齐,但文件说,对齐()属性只能增加的对准和挤得应该用于<青霉>减少的对准

注意事项

从我可以从海湾合作委员会的文件确定,好像有被插入的额外内存3大案要案。


  

      
  1. 结构的内容可能会分配给更多的内存
      结构本身来改变场之间的间距。结果
      有效地,该结构的存储器映射的定义
      结构内的内容可能会改变(虽然不是顺序
      元素)。

  2.   
  3. 结构可能会分配给它们额外的内存来填补
      出来到一个更有效的整体尺寸。这通常是
      旨在使其他变量之一的声明后,未来
      他们的情况不属于同一个块为内
      其中,块是由系统/编译器定义的结构实例。

  4.   
  5. 阵列,无论是结构内与否,可能有额外的
      内存添加到它们的元素转移到一个有效的路线。

  6.   

至于我可以告诉大家,packed属性可以用来影响结构和阻断的情况下,1号及以上2添加了额外的内存,但似乎没有要在处理上述情况3的方式

我编译器(多个)。

问题

有什么办法来保证data_s结构将添加到它或任何其子结构的,所以我没有在内存映射编译器相关的变化绝对没有任何额外的空间?我误解那里的编译器可以插入空间的情况下,故意转移内存映射?

修改

我讨论一些问题与本地大师和它听起来像我有上述情况3的一些误解。阵列中的元素不已插入在它们之间的空间,但额外的空间,以保证它们对准正确被添加到结构本身。显然,这意味着像的sizeof(structureOnlyContaining_uint32_t)不会总是返回4,因为额外的空间可以加入到对齐编译器uint32_t的数据类型被使用。其结果是,实际上只有两种情况:


  

      
  1. 在该结构的存储器映射字段之间更大的偏移。结果
      场之间的空间可被修改,以调整每个字段。
      这可以通过使用包装或对齐()属性改变。

  2.   
  3. 结构结束填充。的大小为一个结构,如通过返回
      的sizeof(),可以进行修改,以便所述结构的阵列最终
      为系统正确对齐。这使得所有系统的假设
      该结构的开始总是会对齐,导致问题
      如果它们不是。这似乎不受包或对齐属性。

  4.   

由于新壳体2的,在一个结构的阵列的元素不一定服从填充或对齐()的结构属性指定,尽管阵列的开始和字段紧跟在阵列做

我的问题是关于再因为作为一个整体,不能纯粹packed属性保证了数组的大小如何packed_2_s处理structArray。有一些方法,以保证structArray场的固定大小作为一个整体?应当注意的是,我不能增加packed_1_s太多的大小,因为结构需要data_s要保持尽可能(其取代在流传输方案的音频/视频数据)。

的小
解决方案

请注意关于 __ __属性有以下几点((包装))


  • 包装在结构声明时,它将COM preSS其等领域,这样,sizeof的(结构)==的sizeof( first_member)+ ... +的sizeof(last_member)。


  • 下面,数组只是结构的一个成员。包装阵列的含结构不会改变阵列的大小。事实上,(任何)数组的大小是始终的sizeof(元素)* number_of_elements。


  • 类似地,包装的内部结构的含结构不会改变内部结构的大小。结构的大小是按它的声明完全确定,并且是一样的,不管你在哪里使用。


  • 包装的结构将使其对准需要一个字节(即,它可以在任何地方在内存中放置)。


  • 访问压缩结构的字段时,包装将引入对齐问题。编译器将占到当字段被直接访问,但不是当他们通过指针访问即可。当然,这并不适用于与对齐要求1字段(如char的或其他打包结构)。见到类似的问题的,它包括一个程序展示的问题通过指针访问成员。


最后,要回答这个问题,


  

有什么办法来保证data_s结构将有
  绝对没有额外的空间增加,或任何其
  子结构,所以我没有在内存编译器相关的变化
  地图吗?


是的。声明结构包装,还以为它包含递归所有结构。

另外请注意,packed属性应用于一个结构声明,而不是一个类型。 有没有这样的东西作为一个结构的包装版本即宣告无包装。当您使用结构的地方,当且仅当该结构本身被宣布它包装(成员)将被包装。这是由这样一个事实结构的大小完全由它的声明来确定种类的暗示。

更新:出于某种原因,你还在困惑阵列。我提供的解决方案(申报携带好所有结构)的适用于阵列过。例如:

 结构elem_struct {
    uint32_t的X;
} __attribute __((包装));
//包装保证的sizeof(结构elem_struct)= sizeof的(uint32_t的)= 4结构array_struct {
    结构elem_struct ARR [10];
} __attribute __((包装));
//包装保证的sizeof(结构array_struct)=
// = sizeof的(结构elem_struct [10])= 10 *的sizeof(结构elem_struct)
// = 10 * 4 = 40

您对阵列进行的另外两个点是真实的 - 但只有当没有包装的结构。包装迫使结构的领域是连续的,而这个的确实的创造,如果没有使用的包装,将插入成员之间的空白和填充的结构解决对齐问题(见点我已经提出了对齐)。

The Problem

I'm working on sending a raw structure over a network to a known program on the other side, but have to worry about the silently introduced memory used for aligning the structures (other issues like endianness are covered). What I'm working with is something like:

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;

I understand that normally the packed_1_s structure could/would have additional space allocated for every instance of the structure to fill it out to the compiler's favored size (dependent on the hardware it's being built for), and that favored size can be anywhere from 2 bytes to 64 bytes (most recently). Normally if I had a single instance of packed_1_s in packed_2_s there would be no problem, but I'm given to understand there's some differences when you try to put elements in an array.

Attempted Solutions

The gcc documentation seems to suggest that by simply including the packed attribute in the packed_2_s definition, the fields, even if they're arrays, will all be as tightly packed as possible and won't add space to the packed_2_s structure to align the elements of the array. The documentation on the align() attribute though suggests that arrays are handled differently than other fields and need the align/packed attribute set on the field directly for it to modify the extra spacing added to match the specified alignment (or lack thereof). I tried setting the packed attribute on both the structArray field, and when that didn't work, did a test by setting the packed attribute on arrayZ in the code above:

packed_1_s structArray[10] __attribute__((packed));

uint8_t arrayZ[20] __attribute__((packed));

Both attempts gave me a compiler warning that the packed attribute wasn't understood in this context and would be skipped (good thing I build with "-Wall").

I hoped a way to get around the issue would be to use attribute align(1), indicating a desired alignment of 1 byte which is comparable to the packed attribute, but documentation says the align() attribute can only increase the alignment and packed should be used to decrease the alignment.

Considerations

From what I can determine from the GCC documentation, it seems like there's 3 major cases of additional memory being inserted.

  1. Structure contents may have additional memory allocated to the structure itself to change the spacing between fields.
    Effectively, the definition of the memory map of the structure contents within the structure may change (though not the order of the elements).
  2. Structures may have additional memory allocated to them to fill them out to a more efficient overall size. This is generally intended so other variables coming after a declaration of one of their instances doesn't fall within the same "block" as the structure instance where a "block" is defined by the system/compiler.
  3. Arrays, whether within a structure or not, may have additional memory added to them to shift the elements to an efficient alignment.

As far as I can tell, the packed attribute can be used to affect the structures and block the additional memory added in case 1 and 2 above, but there doesn't seem to be a way to handle case 3 above on my compiler(s).

The Question

Is there any way to guarantee that the data_s structure will have absolutely no additional space added to it or any of its sub-structures so I don't have compiler dependent shifts in the memory map? Am I misunderstanding the cases where the compiler can insert space to intentionally shift the memory map?

EDIT

I discussed some of the issues with my local guru and it sounds like I have some misunderstanding of case 3 above. The elements in the array don't have space inserted between them, but the additional space to guarantee they align correctly is added to the structure itself. Apparently this suggests things like "sizeof(structureOnlyContaining_uint32_t)" won't always return "4" since additional space may be added to align the uint32_t datatype on the compiler being used. The result is that there are really only 2 cases:

  1. Larger offsets in between fields in the memory map of the structure.
    The space between the fields can be modified to align each field. This can be changed using the packed or align() attributes.
  2. Structure end padding. The size for a structure, as returned by sizeof(), can be modified so arrays of the structures end up correctly aligned for the system. This allows all systems to assume that the start of structures will always be aligned, causing issues if they aren't. This seems unaffected by the pack or align attributes.

Because of the new case 2, elements of an array in a structure don't necessarily obey the packed or align() attributes specified on the structure, though the start of the array and the field immediately following the array do.

My question is then about how to deal with the structArray in packed_2_s since the size of the array as a whole cannot be guaranteed purely by the packed attribute. Is there some way to guarantee the fixed size of the structArray field as a whole? It should be noted that I can't increase the size of the packed_1_s too much since the data_s struct needs to be kept as small as possible (its replacing Audio/Video data in a streaming scenario).

解决方案

Note the following points about __attribute__((packed)):

  • When packed is used in a structure declaration, it will compress its fields such, such that, sizeof(structure) == sizeof(first_member) + ... + sizeof(last_member).

  • Here, an array is just one member of the struct. Packing the containing structure of an array will not change the array's size. In fact, the size of (any) array is always sizeof(element) * number_of_elements.

  • Similarly, packing a containing structure of an inner structure will not change the size of the inner structure. The size of a structure is completely determined by its declaration, and is the same no matter where you use.

  • Packing a structure will make its required alignment one byte (i.e. it can be placed anywhere in memory).

  • Packing will introduce alignment issues when accessing the fields of a packed structure. The compiler will account for that when the the fields are accessed directly, but not when they are accessed via pointers. Of course, this does not apply to fields with required alignment one (such as char's or other packed structures). See my answer to a similar question, which includes a program demonstrating the problem with accessing members via pointers.

Finally, to answer the question,

Is there any way to guarantee that the data_s structure will have absolutely no additional space added to it or any of its sub-structures so I don't have compiler dependent shifts in the memory map?

Yes. Declare the structure as packed, and also all structures that it contains, recursively.

Also note that the packed attribute applies to a structure declaration, and not to a type. There's no such thing as packed version of a structure that is declared non-packed. When you use a structure somewhere, it (its members) will be packed if and only if the structure itself was declared packed. This is kind of implied by the fact that the size of a structure is completely determined by its declaration.

UPDATE: For some reason you're still confused about arrays. The solution I provided (declare all structures packed) works with arrays too. For example:

struct elem_struct {
    uint32_t x;
} __attribute__((packed));
// packed guarantees that sizeof(struct elem_struct) = sizeof(uint32_t) = 4

struct array_struct {
    struct elem_struct arr[10];
} __attribute__((packed));
// packed guarantees that sizeof(struct array_struct) =
// = sizeof(struct elem_struct[10]) = 10 * sizeof(struct elem_struct)
// = 10 * 4 = 40

The two additional points you made about arrays are true - but only when the structures are not packed. Packing forces the fields of the struct to be continuous, and this does create alignment issues which, if no packing was used, would be solved by inserting empty space between members and padding the struct (see the point I already raised about alignment).

这篇关于((包装))结构嵌套阵列上__attribute __的影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆