当其他成员设置为新值时,C 联合成员给出 particular/wrong 值。为什么这个输出在 C 中的以下代码中?

C union member gives particular/wrong value when other member is set to a new value. Why is this output in following code in C?

#include <stdio.h>
int main()
{
  union Data
  {
    char str[20];    
    int i;
    float f;
  }data;

  data.i=20;
  data.f=220.5;
  printf("%d\n",(data.i));

  return 0;
}

输出is:1130135552。我在 Ubuntu 16.04 LTS 上使用了 gcc 编译器。

有人可以解释输出吗?

成员data.idata.f占用相同的内存位置,所以输出应该是220。但是为什么输出是1130135552?

如您所知,union 在内部成员之间共享内存位置。在 union 的情况下,编译器分配的内存等于成员的最大大小,并为所有成员使用相同的内存。

因此,当您执行 data.f=220.5; 时,if 之间的共享内存位置持有 data.i=20; 被覆盖为新值 (220.5),二进制表示如下:

现在,当此值被读取为带符号整数 int 时,它将在没有转换的情况下被解释为十进制表示形式的 1130135552。因此你得到 1130135552.

此外,如果您想使用 union 的所有成员,那么 struct 就是答案。

struct Data
{
    char str[20];
    int i;
    float f;
} data;

data.i=20;
data.f=220.5;
printf("%d\n",data.i);

有关unionstruct的更多信息,请参阅Difference between Structure and Union的以下内容:

根据 C11 第 6.5.2.3 节脚注 95

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

具体输出取决于成员在内存中的布局和类型。因此,当您存储 data.f 然后访问 data.i 时,data.f 内存中的位模式被重新解释为整数。

注意以下几点:

int a = 1;
float b = 1;

这两个虽然在内存上的布局看似相似,但存储方式不同。在整数的情况下,它通常会以二进制补码格式存储(尽管也可以是其他格式),而浮点数通常会使用 IEEE754 格式存储(尽管可以不同) .因此,尝试将使用 IEEE754 存储的数字解释为整数会给您带来完全不同的结果。

另外,不是那个,根据C11 Section 6.2.6.1 Paragraph 7

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

因此,如果你赋值给联合对象的一个​​成员,那么你赋值的成员未使用的其他位置的字节中的值将具有未指定的值。

如果可以的话,让我们将此答案限制在 sizeof(float)sizeof(int) 相同的情况,即 float 是单精度 IEEE754 类型,并且 int 是 2 的补码类型。如果您不明白我在这里说的是什么,请暂时忽略这一段:这是为了让这个答案无懈可击;有点像金融合同中的法律术语。

A float 是一种卓越的类型,能够以极高的精度表示大范围内的数字。它在内部使用的 格式 是一个复杂的格式。如果您想了解更多,请参阅https://en.wikipedia.org/wiki/IEEE_754

当您写入 data.f = 220.5; 时,您正在设置 union 中的第一个 sizeof(float) 字节,以使内存与常量 220.5f.[=27= 相关联]

但是 int 使用完全不同的格式。当你输出 union 的 int 成员时,你用值 1130135552 恢复了 int。这与 220.5f 有关,因为两者具有完全相同的位模式。

union 中的 char str[20]; 是一条红鲱鱼。

data.idata.f共享同一个内存,但是整数和浮点数对一个值的解释是不同的。

使用浮点转换器,您可以获得以下值:

220.5 in float means: 
sign: 1
exponent: 134 
mantissa: 1.72265625 encoded as :6062080

binary representation:0 10000110 10111001000000000000000  (sign, exponent, mant.)
hex representation: 0x435c8000
dezimal representation:1130135552  (the value you get!!)

所明确,标准声明该值未指定。

但是,从实用的角度来说,这是二进制解释的一个很好的例子。

我假设 intfloat 在你的平台上的宽度是 32 位,并且浮点值跟在 IEEE 754 representation.

之后

这里发生了什么:

data.f=220.5;

此语句将浮点值作为二进制 0100 0011 0101 1100 1000 0000 0000 0000 写入 data 的内存位置,覆盖任何先前的值。

下一次访问该值是作为整数读取时:data.i 在您的 printf 调用中访问成员。读取的二进制值仍然是 0100 0011 0101 1100 1000 0000 0000 0000,并且 作为有符号整数,这在没有转换的情况下被解释为 1130135552

如果要转换值,必须将值作为浮点数读取(使用data.f)并使用强制转换将其转换为整数值:

printf("%d\n",(int)(data.f));