2014-07-18 36 views
-3

下面的代码每次输出不同的数字..
apples.num打印2这是正确的,和苹果.weight每次打印不同的数字,它曾经甚至打印出“南”,我不'不知道为什么会发生这种情况..
真的很奇怪的是,双(苹果.volume)打印出2.0 ..

任何人都可以解释给我的东西吗?意外的联盟行为

#include <stdio.h> 

typedef union { 
    short num; 
    float weight; 
    double volume; 
} Count; 

int main(int argc, char const *argv[]) 
{ 
    Count apples; 
    apples.num = 2; 

    printf("Num: %d\nWeight: %f\nVolume: %f\n", apples.num, apples.weight, apples.volume); 
    return 0; 
} 
+6

不要指望未定义的行为被定义。 – chris

+0

您只能将该联合的“short”部分设置为某个值。其余的将包含每次重新运行的随机数据。 – usr2564301

+0

那么男孩假设要做什么?只需选择你苹果的重量从空气 –

回答

3

在我看来,你不太明白什么是工会。一个工会的成员是重叠的价值(换句话说,一个Count工会共享相同的空间三个成员)。

假设,只是为了示范的目的,一个short是16位(2个字节),一个float为32位(4个字节)和一个double为64位(8个字节),则联合是在8个字节尺寸。在little-endian格式中,num成员表示前2个字节,weight成员表示前4个字节(包括num的2个字节),卷成员表示全部8个字节(包括2个字节的numweight的四个字节)。

最初,你的工会装着垃圾,即一些未知的位模式,让我们来显示它像这样(十六进制):

GG GG GG GG GG GG GG GG // GG stands for garbage, i.e. unknown bit patterns 

如果设置num为2,则前两个字节是0x020x00,但其他字节仍然是垃圾:

02 00 GG GG GG GG GG GG 

如果你读weight,你只是阅读的前四个字节,解释为float,所以float包含字节

02 00 GG GG 

由于浮点值有完全不同的格式整型像short,你无法预测这些字节(即表示特定的位模式)。它们不代表浮点值2.0f,这可能是你想要的。实际上,一个float的“更显著”部分存储在高位字节,即在weight的“垃圾”的一部分,因此它几乎可以是任何东西,包括一个NaN+infinity-infinity

同样如果你读volume,你有一个double一个由字节

02 00 GG GG GG GG GG GG 

的,并且不一定代表2。0(尽管偶然,它可能会非常接近,如果巧合,正确的位被设置在正确的位置,并且如果低位在显示这样的值时被舍去)。

联盟并不意味着要进行从intfloatdouble的适当转换。他们仅仅意味着能够为不同类型的值存储到同一类型,并从另一成员阅读为你设置只是意味着你重新诠释一些存在于工会的东西完全不同的位。你不是转换

那么你如何转换?这是很简单的,不需要工会:如果通过“错误”的成员访问联合(即比它通过指定程序以外的其他成员),结果将依赖于语义

short num = 2; 
float weight = num; // the compiler inserts code that performs a conversion to float 
double volume = num; // the compiler inserts code that performs a conversion to double 
+1

值得注意的是,已设置的位是有效位的最低有效16位。控制你是否有NaN,无穷大,有限大,微小有限,正面,负面等的位仍然是垃圾。 –

+1

我可以做到这一点,但我不确定提及术语“指数”,“有效数”等是不会混淆读者而不是帮助他。他只需要知道浮点值具有不同的格式。 –

+0

我用我认为你会理解的术语评论了我的评论。你在用更基本的术语表达信息方面做得很好。同时,有没有人说过如何正确地将整数值转换为相应的float或double值? –

1

您正在访问未初始化的数据。它将提供未定义的行为(即:在这种情况下为未知值)。 You also likely mean to use a struct instead of a union.

#include <stdio.h> 

typedef union { 
    short num; 
    float weight; 
    double volume; 
} Count; 

int main(int argc, char const *argv[]) 
{ 
    Count apples = { 0 }; 
    apples.num = 2; 

    printf("Num: %d\nWeight: %f\nVolume: %f\n", apples.num, apples.weight, apples.volume); 
    return 0; 
} 

由要么归零出来,还是最大的成员设置的值初始化工会。即使你设置了最大的成员,其他值也许没有意义。 This is commonly used for creating a byte/word/nibble/long-word data type and making the individual bits accessible.

+2

平心而论,这仍然不是浮动转换的* int,因为OP似乎认为它是。 – usr2564301

+0

他总是可以做一些像“apples.weight = 1.0f”一样的东西,并检查有效性。 – DevNull

+0

清除了一些东西,我认为工会使用了一些隐式转换.. –

2

该类型的特定位模式。如果指定的类型具有较小的访问类型的位宽,则其中一些位将不确定。

+0

我想通了,我必须使用枚举.. –

+0

@AmrAyman:我不知道你的意思。我怀疑你实际需要的是类型转换。 – Clifford