当其他成员设置为新值时,C联合成员给出了特定/错误的值。为什么这个输出在C中的以下代码中? #包括 int main() { 联合数据 { char-str[20]; int i; 浮动f; }数据; 数据i=20; 数据f=220.5; printf(“%d\n”,(data.i)); 返回0; }
输出为:113013552。我在Ubuntu 16.04 LTS上使用了gcc编译器 有人能解释一下输出吗当其他成员设置为新值时,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),二进制表示如下: 现在,当该值被读取为带
成员
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));