c 中的 union 一次存储一个数据

union in c stores one data at a time

如果内存中分配的联合大小等于最大数据类型成员(以字节为单位)那么谁能告诉我编译器如何存储和获取两个数据 double d 和 int i(总共 8+4 个字节)(double在我的机器上是 8 个字节)。

#include<stdio.h>
union test {

    int i;
    double d;

};

int main()
{
   union test obj;
   obj.d=15.5;
   obj.i=200;

   printf("\nValue stored in d is %f",obj.d);
   printf("\nValue stored in i is %d",obj.i);
   printf("\n size of obj is %d ",sizeof(obj));

}

**Output is : Value stored in d is 15.500000
Value stored in i is 200
 size of obj is 8**

我认为它并不像您想象的那样有效。如果您在测试中添加更多内容:

#include<stdio.h>
union test {
    int i;
    double d;
};

int main()
{
   union test obj;
   obj.d=15.5;
   obj.i=200;

   printf("\nValue stored in d is %f",obj.d);
   printf("\nValue stored in i is %d",obj.i);
   printf("\n size of obj is %d ",sizeof(obj));

   obj.d=17.5;

   printf("\nValue stored in d is %f",obj.d);
   printf("\nValue stored in i is %d",obj.i);
   printf("\n size of obj is %d ",sizeof(obj));

   obj.i=300;

   printf("\nValue stored in d is %f",obj.d);
   printf("\nValue stored in i is %d",obj.i);
   printf("\n size of obj is %d ",sizeof(obj));

}

输出为:

$ ./main 

Value stored in d is 15.500000
Value stored in i is 200
 size of obj is 8 
Value stored in d is 17.500000
Value stored in i is 0
 size of obj is 8 
Value stored in d is 17.500000
Value stored in i is 300
 size of obj is 8 

注意中间的i值是0!那是因为它被(部分?)覆盖了。

如果我理解正确的话,那是未定义的行为,你看到的确切值将取决于你编译它的体系结构、编译器用于此结构的对齐等等。

编辑:

我想我现在理解了原来的问题 -- 它是关于为什么完全可以恢复第一个存储值的,对吧?为什么我看不到乱码而不是 200。

我的猜测是它可能取决于浮点数的一些实现细节?如果它是像 17.5 这样的 "simple" double,也许 double 碰巧不会覆盖 "int" 的位。不完全确定。编辑:参见 "imreal" 的回答。

您可以将 id 存储到您的联合,但不能同时存储两者。语句

obj.i=200;  

覆盖存储在为联合分配的内存中的值。现在使用 %f 说明符访问 obj.d 将调用未定义的行为,这是因为 obj 中存储的值是 int.

您似乎可以将两个数字存储在重叠内存中的原因是您选择的小值的排列方式。

如果您尝试需要存储更多信息的值,例如:

obj.d=100000000000000;
obj.i=0xffffffff;

您会看到打印 double 值的输出有所不同:

Value stored in d is 100000059097087.984375

它可以存储两者的方式是 "pure luck"。我只是假设您的计算机体系结构使用 IEEE 754 浮点数并尝试解释您所看到的内容。您的联合确实只使用了八个字节,但是 15.5 的十六进制看起来像这样:402F000000000000。如您所见,低四个字节完全为零。现在让我们将最低的四个字节设置为整数 200,看看八个字节的值会发生什么。这给了我们 402F0000000000C8。现在假设您现在将所有八个字节作为双精度读回,在 IEEE754 中您得到 15.500000000000355 打印时将四舍五入为 15.5 使得联合可以存储双精度和整数。

所有这些都说像这样访问联合体的两个成员在 C++ 中是未定义的行为,至少在 C++11 之前是这样(尽管它在我所知道的所有平台上的行为都是合乎逻辑的),所以这个只是对您观察到的行为的一种可能解释。不过在 C 中它似乎是完全合法的。

写入 obj.i 后,从 obj.d 读取是未定义的行为,就 C 标准而言,任何事情都可能发生。

在这种特殊情况下,您可能不会看到任何事情发生,因为浮点数被放置在内存中。您正在更改尾数的一些最低有效位,创建前 6 个十进制数字中看不到的更改。添加更多数字:

printf("\nValue stored in d is %.17f",obj.d);

你会得到:

Value stored in d is 15.50000000000035705