打印联合变量 - 奇数行为

时间:2014-10-03 14:29:08

标签: c printf unions type-punning

#include <stdio.h>

union p{
    int x;
    float y;
};

int main()
{
    union p p;
    p.x = 10; 
    printf("%f\n", p.y);
    return 0;
}

输出:

  

0.000000

当我尝试编译上述程序时,它没有显示任何警告, 即使在主要功能。为什么printf无法打印价值10.00000

我已经阅读了一些关于 stackoverflow 的相关问题,它解释了printf在打印整数时没有使用浮点说明符进行类型转换的行为,但我认为这是一个不同的情况。我用float说明符打印浮点数。它应该打印正确的值。谁能解释一下这里发生了什么?

3 个答案:

答案 0 :(得分:5)

这是因为intfloat对象都有不同的二进制表示。假设32位intfloat,little-endian和IEEE-754表示,你有二进制模式:

0000 1010 0000 0000 0000 0000 0000 0000

即(在浮点数的上下文中)非常小的数字,其使用0.000000格式说明符打印值为%f(可以说是printf四舍五入)。您可以尝试使用%e f.s.,这会产生另一个输出:

1.401298e-44

C99引入%a f.s.,它表示存储的浮点数,即2基点浮点数(即尾数和指数):

0x1.4p-146

答案 1 :(得分:4)

你把10整数放入x。 如果你写p.x = 1092616192而不是p.x = 10,你会看到会发生什么 另请阅读https://en.wikipedia.org/wiki/IEEE_floating_point

10在内存中不等于10.f.

答案 2 :(得分:3)

具有不同二进制表示的

int float ,如果您尝试以科学格式%e进行打印,则会看到p.f的以下值:

  

1.401298E-44

假设IEEE 754 single precision float4字节 int ,让我们尝试float convertor来查看有效的十六进制值对于let&# 39;用 IEEE 754 格式表示值40

40插入转换器会产生十六进制值:

  

0x42200000

如果我们将此值分配给p.x

p.x = 0x42200000;

当您打印40see it live时,您会看到值p.y退出。

关于通过联合的类型惩罚是否是未定义的行为,这一直是一个争论,据我所知它不是,并且在实践中编译器明确支持这种类型的惩罚,这里是the gcc reference explaining its support