与共同第一成员的结构联盟

时间:2013-12-23 22:30:17

标签: c struct unions

我不确定代码是否在断言转换中具有指针别名(或其他标准一致性问题)。似乎指向联合类型的指针应该能够转换为第一个成员的指针,因为联合只由这两个结构组成,我认为对第一个成员的强制转换应该有效,但我不是确定这是否正确,或者我是否在过程中掩盖了填充细节。工会是否需要填补高位?

这似乎是未指明的行为?有没有人知道这是否被支持。我知道有一种替代的标准方法可以通过使用带有enum type字段和struct container_storage成员的结构来实现这一点,但考虑到此信息已经在{{1}中,这似乎是浪费空间}}

linux中的

编译命令:struct contained返回gcc -std=c99 -Wextra -pedantic -fstrict-aliasing test.c && ./a.out && echo $?

0

参考文献:

[1] gcc, strict-aliasing, and casting through a union

[2] What is the strict aliasing rule?

3 个答案:

答案 0 :(得分:4)

那应该没问题。 C11,6.5.2.3/6(“结构和工会成员”)说:

  

为了简化工会的使用,我们提出了一项特殊保证:如果工会包含   几个结构共享一个共同的初始序列(见下文),如果是联盟   对象当前包含这些结构中的一个,允许检查公共结构   其中任何一个的初始部分都是完整类型的联盟的声明   是可见的。如果相应的成员,两个结构共享公共初始序列   对于一个或多个序列具有兼容类型(并且对于位字段,具有相同的宽度)   初始成员。

(C ++为标准布局联合提供了相同的保证(C ++ 11,9.2 / 18)。)

答案 1 :(得分:2)

union不填,他们只是覆盖他们的成员。保证任何struct的第一个成员立即开始,没有填充。一般来说,以相同类型的相同成员开头的struct保证为该初始部分具有相同的布局。

答案 2 :(得分:1)

在C89下,标识联合成员的结构类型的指针可用于检查作为与其中存储的数据类型共享的公共初始序列的一部分的任何成员。这反过来通常意味着可以使用指向任何结构类型的指针来检查与任何其他类型共享的公共初始序列的任何成员(如果该对象恰好是声明的联合对象的成员,则这种行为将被明确定义并且编译器在这些情况下产生所需行为的唯一实用方法是为所有人维护它。

C99增加了一项附加要求,即CIS保证仅在包含两种结构的完整联合类型可见时才适用,一些编译器编写者认为这意味着它仅适用于直接通过联合类型执行的访问。这些编译器的作者似乎认为一个函数需要处理具有公共标题的函数,如:

struct smallThing { void *next; uint16_t length; uint8_t dat[2]; };
struct bigThing { void *next; uint16_t length; uint8_t dat[65528]; };

应该是提取标题,如:

struct uHeader {  void *next; uint16_t length; };
struct smallThing { uHeader head; uint8_t dat[2]; };
struct bigThing { uHeader head; uint8_t dat[15994]; };

或者为所有东西使用union-type对象,即使使用uHeader也是如此 将struct smallThing的大小增加50%(并完全破坏任何代码 它一直依赖于它的布局),并且当大多数对象只需要很小的时候使用工会就可以将内存使用量提高一千倍。

如果需要代码与基本上忽略公共初始序列规则的编译器兼容,则应该将公共初始序列规则视为基本无用。就个人而言,我认为最好记录只有符合CIS的编译器应该被认为适合用于代码,而不是向后弯曲以适应不合适的编译器,但我认为它很重要要知道像后者那样的编译器存在。

据我所知,clang和gcc不会以任何有用的方式遵守CIS规则,除非设置了-fno-strict-aliasing标志。我不了解其他编译器。