是通过C99中未指定的联合进行types化处理,并在C11中指定?
堆栈溢出问题的一些答案获取浮点的IEEE单精度位提示使用union
结构进行types双关(例如:将float
的位转换为uint32_t
):
union { float f; uint32_t u; } un; un.f = your_float; uint32_t target = un.u;
但是,根据C99标准(至less草案n1124),联合体的uint32_t
成员的值似乎未指定,其中第6.2.6.1.7节指出:
当一个值存储在uniontypes的对象的成员中时,不与该成员相对应但与其他成员相对应的对象表示的字节取未指定的值。
C11 n1570草案至less有一个脚注似乎暗示这不再是这种情况(见6.5.2.3脚注95):
如果用于读取联合对象内容的成员与上次用于在对象中存储值的成员不相同,则该值的对象表示forms的适当部分将被重新解释为新types中的对象表示forms,如如6.2.6所述(一个有时称为“types双关”的过程)。 这可能是一个陷阱代表。
不过,C99草案中的第6.2.6.1.7节的内容与C11草案中的内容相同。
这个行为在C99下实际上是不确定的吗? 它已经在C11中指定了吗? 我意识到,大多数编译器似乎支持这一点,但它是很好的知道,如果它在标准中指定,或者只是一个非常常见的扩展。
联合types双关的行为从C89改为C99。 C99中的行为与C11相同。
正如Wug在他的回答中指出的那样,在C99 / C11中允许打字。 当联盟成员大小不同时,可以读取一个可能成为陷阱的未指定值。
Clive DW羽毛缺陷报告#257中添加了脚注C99:
最后,从C90到C99的变化之一是,当最后一个店铺到另一个店铺时,取消对访问一个工会成员的任何限制。 理由是,行为将取决于价值的表征。 由于这个问题经常被误解,所以在标准中可能很清楚。
[…]
为了解决“types双关”的问题,在6.5.2.3#3中添加一个新的脚注78a到“named member”:78a如果用于访问联合对象内容的成员与最后一个成员不相同用于在对象中存储一个值,值的对象表示的适当部分被重新解释为新types的对象表示,如6.2.6(有时称为“types双关”的过程)中所述。 这可能是一个陷阱代表。
克莱夫DW羽的措辞已经被C C 第283号委员会的答复接受了技术勘误。
原来的C99规范没有说明这一点。
对C99的技术勘误之一(TR2,我认为)增加了脚注82来纠正这种疏漏:
如果用于访问联合对象内容的成员与上次用于在对象中存储值的成员不相同,则该值的对象表示的相应部分将被重新解释为新types中的对象表示forms,如如6.2.6所述(一个有时称为“types双关”的过程)。 这可能是一个陷阱代表。
该脚注保留在C11标准中(C11中的脚注95)。
这一直是“iffy”。 正如其他人所指出的那样,通过技术更正会议,C99增加了一个脚注。 内容如下:
如果用于访问联合对象内容的成员与上次用于在对象中存储值的成员不相同,则该值的对象表示的相应部分将被重新解释为新types中的对象表示forms,如如6.2.6所述(一个有时称为“types双关”的过程)。 这可能是一个陷阱代表。
但是,在前言中将脚注指定为非规范性的:
附件D和F构成本标准的规范性部分; 附录A,B,C,E,G,H,I,J,参考书目和索引仅供参考。 根据ISO / IEC指令第3部分, 本前言,引言,注释,脚注和示例仅供参考 。
也就是说,脚注不能禁止行为; 他们只应该澄清现有的文字。 这是一个不受欢迎的意见,但上面引用的脚注在这方面实际上是失败的 – 在规范性文本中没有这种行为被禁止。 的确,有一些部分如6.7.2.1:
…至多其中一个成员的值可以随时存储在联合对象中
结合6.5.2.3(关于使用“。”运算符访问工会成员):
值是指定成员的值
即如果只能存储一个成员的值,则另一个成员的值是不存在的。 这强烈暗示了通过工会进行打字是不可能的。 成员访问会产生一个不存在的值。 C11文档中仍然存在相同的文本。
不过,join脚注的目的很明显是允许打字; 这只是委员会似乎打破了不包含规范性文本的脚注规则。 为了接受这个脚注,你真的不得不忽视脚注不是规范性的部分,否则就会试图找出如何解释规范性文本以支持脚注的结论(我已经尝试过了,失败了,要做)。
您引用的部分:
当一个值存储在uniontypes的对象的成员中时,不与该成员相对应但与其他成员相对应的对象表示的字节取未指定的值。
但是必须仔细阅读。 “ 与该成员不对应的对象表示的字节”指的是超出成员大小的字节,这本身不是一个types双关的问题(除非你不能假定写入联合成员会离开任何更大的成员的“额外”部分不变)。
但是,这似乎违反了C99标准(至less草案n1124),其中第6.2.6.1.7部分陈述了一些东西。 这个行为在C99下实际上是不确定的吗?
不,你没事。
当一个值存储在uniontypes的对象的成员中时,不与该成员相对应但与其他成员相对应的对象表示的字节取未指定的值。
这适用于不同大小的数据块。 也就是说,如果你有:
union u { float f; double d; };
你给f赋了一些东西,它会改变d的低4字节,但高4字节将处于不确定状态。
工会主要是为了打字而存在的。