2014-10-03 39 views
4
#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

我已经阅读计算器这也解释了在打印过程中没有使用float符类型转换整数printf行为的一些相关的问题,但我在这里想这是一个不同的情况。我正在用float说明符打印浮点数。它应该打印适当的值。任何人都可以解释这里发生了什么?

+2

由于int和float的内存表示方式不同(请查看调试器,您会看到)。此外写p.x和访问p.y是未定义的行为... – 2014-10-03 14:31:47

+1

@AdrianoRepetti; “访问p.y是未定义的行为”:否。不是这种情况。 – haccks 2014-10-03 14:32:32

+1

@haccks AFAIK这不是如果'int'和'float'具有相同的大小(实际上如果它们是_compatible types_)但它不是必需的(它们在这里并不知道,因为它取决于环境)。如果我没有错... – 2014-10-03 14:35:11

回答

4

您将10个整数放入x中。 如果你写p.x = 1092616192而不是p.x = 10你会看看会发生什么 也读https://en.wikipedia.org/wiki/IEEE_floating_point

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

+2

这是假设'int'是4个字节,这可能不是 – 2014-10-03 14:46:53

+0

......如果不是这样会导致UB。 – 2014-10-03 14:49:08

+0

如果你想迂回,没有保证,float也会有4个字节。然而,目前所有常见的体系结构都有int和float四个字节。顺便说一句,更好的链接,看到4字节的浮动布局:https://en.wikipedia.org/wiki/Single-precision_floating-point_format – 2014-10-03 15:06:35

5

这是由于以下事实:intfloat对象具有不同的二进制表示形式。假设32位intfloat,小端和IEEE-754表示,则都具有二进制图案为:

0000 1010 0000 0000 0000 0000 0000 0000 

即(在浮点数的上下文中)非常小的数目,这已使用打印的值作为0.000000格式说明符(%f)(可以这样说,它被取整为printf)。你可以尝试用%e FS,这将导致到另一个输出:

1.401298e-44 

C99推出%a FS,表示正是因为它的存储,即作为2基浮点数(与尾数和指数即浮数):

0x1.4p-146 
3

INT浮动具有不同的二进制表示,如果你试图在科学格式%e打印你会看到下面的值p.f

1.401298E,44

所以假设IEEE 754 single precision float4字节INT,让我们尝试float convertor,看看有什么有效的十六进制值将是我们说的价值40IEEE 754格式。

堵在40到转换器提供了十六进制值:

0x42200000

如果我们指定此值p.x

p.x = 0x42200000; 

您将看到价值40回来了当您打印p.y时,see it live

这总是一个关于是否通过联合的类型剔除是未定义的行为的辩论,据我了解它不是,并且在实践中编译器明确支持这种类型的剔除,这里是the gcc reference explaining its support