当其他成员设置为新值时,C联合成员给出了特定/错误的值。为什么这个输出在C中的以下代码中? #包括 int main() { 联合数据 { char-str[20]; int i; 浮动f; }数据; 数据i=20; 数据f=220.5; printf(“%d\n”,(data.i)); 返回0; }

当其他成员设置为新值时,C联合成员给出了特定/错误的值。为什么这个输出在C中的以下代码中? #包括 int main() { 联合数据 { char-str[20]; int i; 浮动f; }数据; 数据i=20; 数据f=220.5; printf(“%d\n”,(data.i)); 返回0; },c,unions,C,Unions,输出为:113013552。我在Ubuntu 16.04 LTS上使用了gcc编译器 有人能解释一下输出吗 成员data.i和data.f占用相同的内存位置,因此输出应该是220。但是为什么输出是113013552?因为您已经知道,联合在内部成员之间共享内存位置。在联合的情况下编译器分配的内存等于成员的最大大小,并对所有成员使用相同的内存 因此,当您执行data.f=220.5时,在持有数据的i和f之间的共享内存位置。i=20被覆盖为新值(220.5),二进制表示如下: 现在,当该值被读取为带

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

有人能解释一下输出吗


成员
data.i
data.f
占用相同的内存位置,因此输出应该是220。但是为什么输出是113013552?

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

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

现在,当该值被读取为带符号整数
int
时,它将在不进行转换的情况下被解释为十进制形式的
113013552
。因此,您将获得
1130135552

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

#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;
}
有关
union
struct
的更多信息,请参阅以下内容:

根据C11第6.5.2.3节脚注95

如果用于读取联合对象内容的成员不是 与上次用于在对象中存储值的成员相同, 值的对象表示的适当部分是 重新解释为新类型中的对象表示形式,如上所述 在6.2.6中(有时称为“类型双关”的过程)。这可能是 陷阱表示法

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

注意以下几点:

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

data.i=20;
data.f=220.5;
printf("%d\n",data.i);
这两个虽然看起来在内存上有相似的布局,但它们的存储方式不同。在整数的情况下,它通常以2的补码格式存储(尽管它也可以是其他格式),浮点通常使用该格式存储(尽管它可以不同)。因此,尝试将使用IEEE754存储的数字解释为整数将得到完全不同的结果

此外,根据C11第6.2.6.1节第7段,并非如此

当值存储在联合类型的对象的成员中时 与之不对应的对象表示形式的字节数 成员,但与其他成员相对应,并采用未指定的值


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

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

float
是一种非常出色的类型,能够以非常高的精度在很大范围内表示数字。它内部用于实现这一点的格式是复杂的。如果您想了解更多信息,请参阅

当您写入
数据时,f=220.5
,您正在设置
联合中的第一个
sizeof(float)
字节,以使内存与常量
220.5f
关联

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


charstr[20]联合体中的code>是一条红鲱鱼。

数据.i
数据.f
共享相同的内存,但对值的解释在整数和浮点上是不同的

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

int a = 1;
float b = 1;
如所述,标准声明该值未指定

然而,从实用角度来说,这是一个二元解释的好例子

我假设您平台上的
int
float
的宽度为32位,浮点值紧跟其后

这里发生了什么:

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!!)
此语句将浮点值作为二进制
0100 0011 0101 1100 1000 0000
写入
数据
的内存位置,覆盖以前的任何值

下一次访问该值是在读取为整数时:
data.i
printf
调用中访问成员。以二进制形式读取的值仍然是
0100 0011 0101 1100 1000 0000
,并且是一个有符号整数,无需转换即可解释为
113013552

如果要转换该值,必须以浮点形式读取该值(使用
data.f
),然后使用强制转换将其转换为整数值:

data.f=220.5;

@用户694733:我不明白你的意思。你能详细说明一下吗?另外,看看我的更新。我是说6.2.6.1不相关,可以删除。它指定从
data.str[4]
data.str[19]
的字节发生了什么变化。您从6.5.2.3中添加的内容是正确的。您是对的,6.5.2.3没有直接关系,但绝对重要。但6.5.2.3是精确的。我会重组
printf("%d\n",(int)(data.f));