共同第一成员的结构联盟

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

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

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

 #include  #include  enum type {type_a = 1, type_b = 2}; struct contained { int some_other_field; enum type type; }; struct container_a { struct contained contained; int test; }; struct container_b { struct contained contained; char test; }; union container_storage { struct container_a container_a; struct container_b container_b; }; int main(int argc, char **argv) { union container_storage a = {.container_a = {.contained = {.type = type_a}, .test = 42}}; union container_storage b = {.container_b = {.contained = {.type = type_b}, .test = 'b'}}; assert(((struct contained *)&a)->type == type_a); assert(((struct contained *)&b)->type == type_b); return EXIT_SUCCESS; } 

参考文献:

[1] gcc,严格别名,并通过联合进行转换

[2] 什么是严格别名规则?

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

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

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

union没有垫,他们只是覆盖他们的成员。 任何struct的第一个成员都保证在没有填充的情况下立即启动。 通常,以相同类型的相同成员开头的struct保证具有该初始部分的相同布局。

在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类型的对象,即使使用uHeader会将struct smallThing的大小增加50%(并且完全破坏任何依赖于其布局的代码),并且当大多数对象只需要时使用联合。小会增加内存使用量千倍。

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

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