【发布时间】:2012-07-23 07:22:18
【问题描述】:
Stack Overflow 问题Getting the IEEE Single-precision bits for a float 的一些答案建议使用union 结构进行类型双关语(例如:将float 的位转换为uint32_t):
union {
float f;
uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
但是,根据 C99 标准(至少是草案 n1124),工会的 uint32_t 成员的值似乎未指定,其中第 6.2.6.1.7 节规定:
当一个值存储在联合类型对象的成员中时,对象表示中与该成员不对应但与其他成员对应的字节采用未指定的值。
C11 n1570 草案的至少一个脚注似乎暗示这不再是这种情况(参见 6.5.2.3 中的脚注 95):
如果用于读取联合对象内容的成员与上次用于读取的成员不同 在对象中存储一个值,该值的对象表示的适当部分被重新解释 作为 6.2.6 中描述的新类型中的对象表示(有时称为“类型 双关语'')。这可能是一个陷阱表示。
但是,C99 草案中的第 6.2.6.1.7 节的文本与 C11 草案中的相同。
这种行为在 C99 下实际上是未指定的吗?是否已在 C11 中指定?我意识到大多数编译器似乎都支持这一点,但如果知道它是在标准中指定的,还是只是一个非常常见的扩展,那就太好了。
【问题讨论】:
-
技术说明:访问存储的最后一个以外的联合成员不会导致程序违反 C 标准。访问这样的联合成员会导致未指定的值(不是未定义的行为),并且根据 C 1999 4 3,“应是正确的程序并按照 5.1.2.3 行事。”此外,编译器可能会提供有关该值的额外保证并保持一致的实现。
-
@DanielFischer:n1124 和 n1570 草案都明确列出未指定:附录 J 中的“除了最后一个存储到 (6.2.6.1) 中的联合成员的值”(可移植性问题)。对我来说,这似乎意味着可能存在一个 C99(或 C11)编译器,其中使用联合进行类型双关语不能达到我们的预期。
-
再读一遍,它说那些 bytes 对应于另一个成员,而不是那些被写入具有未指定值的成员。这意味着与该成员相对应的字节(因此两者共有的字节)具有特定值,即写入的那个值。这一段只是用来解释未写入的字节会发生什么(或不发生),仅此而已。
-
@sfstewman,附录 J 不规范。
-
@EricPostpischil:如果在写入第一个值和读取第二个值之间,代码要检查联合字段占用的字节,标准将指示这些字节必须包含的内容。我不知道旧标准中的任何内容都会阻止编译器,例如将联合中的
float优化为 FPU 寄存器,并将其覆盖的int优化为 CPU 寄存器,并仅在char*别名规则强制执行时将这些寄存器读/写到内存。
标签: c c99 unions c11 type-punning