#include<stdio.h>
union U{
struct{
int x;
int y;
};
float xy;
};
int main(){
union U u;
u.x = 99;
printf("xy %f\n",u.xy); //output " 0 "
return 0;
}
我已经发现这与内部如何存储和读取浮点数有关。是否有人可以准确地向我解释一下?
将评论转换为答案。
使用%f
打印不是很有用;您应该考虑使用%g
或%e
。使用%f
时,如果值非常小,则即使它不为零,也会被打印为0.000000
。(例如,任何小于0.0000005
的值都将被打印为0.000000
。)您需要阅读维基百科上关于IEEE 754的内容,以了解这些值是如何表示的。
例如,在运行macOS Sierra 10.12.5的Mac上使用GCC 7.2.0进行打印:
printf("xy %22.16g\n", u.xy);
产生:
xy 1.387285479681569e-43
float
类型中正常数值范围通常为10⁺³⁸到10⁻³⁸,因此float
类型的值1.387…E-43
是次标准值(尽管在8字节的double
类型值的范围内)。请记住,由于“默认参数提升”,传递给printf()
的float
类型值会自动提升为double
类型值,因此printf()
实际上永远不会接收到float
类型的值。浮点数的表示方式会影响结果。请参考C语言中如何在内存中表示浮点数和https://softwareengineering.stackexchange.com/questions/215065/can-anyone-explain-representation-of-float-in-memory来了解浮点数在内存中的表示方式。您还没有初始化结构体变量y
,它可能具有任何值,可能被使用也可能不被使用。在您的情况下,该值非常小,您未打印完整值。为了查看float
xy
的值,您需要打印完整值。正如在这里的评论中建议的那样,在Windows(包含MinGW编译器)上使用Codeblocks 16.1中的以下语句,我得到的值与0.000000不同。
printf("xy %.80f\n",u.xy);
给我 xy 0.00000000000000000000000000000000000000000013872854796815689002144922874570169700
是的,你说得对,这与浮点值的二进制表示有关,该表示在标准文档IEEE 754中定义。请参阅Steve Hollasch的这篇优秀文章以获得简单的解释。浮点数是32位值,整数也是如此。因此,在您的联合U中,xy恰好落在嵌入式结构的x成员上,因此当您将x设置为99时,1100011(99的二进制表示)的位将被重新解释为float的尾数。正如其他人指出的那样,这是一个非常小的值,具体取决于printf格式说明符,可能会打印为0。
从您的联合成员的命名(x,y,xy)猜测,我认为您想声明不同的内容,例如:
union U
{
struct
{
short x;
short y;
};
float xy;
};
或者:
union U
{
struct
{
int x;
int y;
};
double xy;
};
原因是该值非常接近于零,所以默认的6位精度无法显示任何内容。
尝试:
union { int i; float f; } u = {.i= 99};
printf("f %g\n", u.f);
printf("xy %.80f\n",u.xy);
- Support Ukraine
%f
进行打印并不是特别有用;你应该考虑使用%g
或%e
。如果值非常小,即使它不为零,它也会打印为0.000000
。(例如,任何比0.0000005
更小的值都将打印为0.000000
)。您需要阅读 IEEE 754 的维基百科页面,以了解这些值如何表示。例如,在运行macOS Sierra 10.12.5和GCC 7.2.0的Mac上,使用printf("xy %22.16g\n", u.xy);
将生成xy 1.387285479681569e-43
。 - Jonathan Leffleru
中未命名结构体的成员x
。然后他使用另一个联合体成员xy
来读取内容。有可能会出现陷阱表示,这种情况下代码的行为将是未定义的。 - haccksfloat
类型中正常数值的范围通常为10⁺³⁸到10⁻³⁸,因此float
类型中的1.387…E-43是一个次标准值(尽管在8字节的double
类型值的范围内)。 - Jonathan Lefflery
在此代码中未被访问,如果sizeof(float) <= sizeof(int)
。 - M.M.xy
未初始化,并且对.x
的写入是无效的。因此,它可能会将代码编译为int main(){ printf(“xy%f \ n”,0.0); }
,完全优化联合的使用。 我相信,将int
的位重新解释为float
的唯一安全方法是使用memcpy()
:int x = 99; float xy; memcpy(&xy,&x,sizeof(float));
- cmaster - reinstate monica