C 使用printf打印浮点值 #包括 #包括 内部主(空) { int x,*ptr_x; 浮点数f,*ptr\u f; ptr_f=&f; ptr_x=&x; *ptr_x=5; *ptr_f=1.5;//printf(“%d%f\n”,f,x); printf(“\n\nxd=%d\t xf=%f\n ff=%f\t fd=%d”,x,x,f,f); 返回0; }

C 使用printf打印浮点值 #包括 #包括 内部主(空) { int x,*ptr_x; 浮点数f,*ptr\u f; ptr_f=&f; ptr_x=&x; *ptr_x=5; *ptr_f=1.5;//printf(“%d%f\n”,f,x); printf(“\n\nxd=%d\t xf=%f\n ff=%f\t fd=%d”,x,x,f,f); 返回0; },c,pointers,printf,C,Pointers,Printf,ff=%f的输出不是预期的 xd=5 xf=0.000000 ff=0.000000 fd=1073217536 这段代码的目的是显示若用%d打印浮点值,若用%f打印int值,会发生什么情况 为什么即使使用%f,浮点值也无法正确打印?printf()不是类型安全的。 传递给printf()的参数将根据您向编译器承诺的内容进行处理 另外,floats在通过可变参数时被提升为doubles 因此,当您第一次向编译器承诺%f(对于xf)时,编译器会从参数中吞下整个双(通常为8字节),并在过程中吞下

ff=%f的输出不是预期的

xd=5 xf=0.000000
ff=0.000000 fd=1073217536

这段代码的目的是显示若用%d打印浮点值,若用%f打印int值,会发生什么情况

为什么即使使用%f,浮点值也无法正确打印?

printf()不是类型安全的。

传递给
printf()
的参数将根据您向编译器承诺的内容进行处理

另外,
float
s在通过可变参数时被提升为
double
s

因此,当您第一次向编译器承诺
%f
(对于
xf
)时,编译器会从参数中吞下整个
(通常为8字节),并在过程中吞下您的浮点值。然后第二个
%f
正好切入第二个双精度的零尾数

下面是你的论点的图片:

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
  int x, *ptr_x;
  float f , *ptr_f;

  ptr_f = &f;
  ptr_x = &x;
  *ptr_x = 5;
  *ptr_f = 1.5; //printf("%d %f\n", f,x);

  printf ("\n\nxd = %d \t xf = %f \n ff = %f \t fd = %d", x,x,f,f);
  return 0;
}
但是
f
看起来像这样(被提升为
double
):

让我们用值再次绘制它,并推测您的机器端性:

f = 3FF8000000000000
请注意,1073217536是0x3FF80000。

请尝试以下操作:

| 05000000 | 05000000 | 00000000 0000F83F | 00000000 0000F83F |
| %d, OK   | %f, denormal...    | %f, denormal...   | %d, OK  |
调用
printf()
时,系统将参数推送到堆栈上。所以堆栈看起来像这样:

printf("size of int = %d, size of float = %d, size of double = %d\n",
    sizeof(int), sizeof(float), sizeof(double));
然后
printf()
在解析格式字符串时从堆栈中弹出字节。当它看到
%d
时,会弹出足够的字节来表示int,当它看到
%f
时,会弹出足够的字节来表示float。(实际上,当浮点数作为函数参数传递时,浮点数会被提升为双倍,但重要的是它们需要的字节比int多。)因此,如果你对参数“撒谎”,它会弹出错误的字节数,并根据你的指令盲目地转换它们

因此,它将首先弹出
xd
的正确字节数,因为您已经正确地告诉它x是一个int

但随后它将弹出足够的字节来进行浮点运算,这将消耗堆栈中的第二个
x
和第一个
f
的一部分,并将它们解释为
xf
的浮点运算

然后,它将弹出足够的字节,用于另一个浮点,这将消耗第一个
f
的剩余部分和第二个
f
的一部分,并将它们解释为
ff
的浮点

最后,它将弹出足够多的字节来表示int,这将消耗第二个
f
的剩余字节,并将它们解释为
fd
的int

希望这能有所帮助。

一旦您将至少一个无效的格式说明符传递给
printf
(比如尝试用
%d
打印
浮点值,或者用
%f
打印
int
值),您的整个程序就会变得一团糟,无法修复。这种破坏性行动的后果可以在该计划的任何地方看到。在您的情况下,尝试使用无效的格式说明符打印某些内容会导致即使是有效的格式说明符也停止工作

正式地说,您编写了一个显示未定义行为的程序。它的行为完全不可预测。你自己说的

这段代码的目的是显示若一个浮点 值用%d打印,如果打印的是整型值%f


你观察到的坏行为正好证明了这一点当您尝试这样做时,一个奇怪且不可预测的表演程序正是发生的事情。

这是高度定义的实现。对于某些编译器来说,这可能是正确的。对其他人来说——不是。例如,一些现代64位编译器在8字节字段中传递所有可变参数,而不管它们的实际大小(而不是像图中那样将它们紧密打包)。如果OP使用这样的编译器,问题可能会隐藏起来。是的,关于这个答案的一切都完全依赖于机器,充满了猜测和虚构。关于它唯一可移植的部分是最初的警告。哇,非常感谢您花时间创建这样一个有用的图表,太棒了!但是为什么以及如何提升浮动呢?如果我将浮点传递给用户定义的函数,是否会发生类似的情况?你说的可变参数是什么意思。。我还在谷歌上搜索变量函数。。我不明白为什么需要提升。@tera:提升只是可变参数规则的一部分。我头上没有参考资料,但如果你愿意,我可以查一下。Chars和短裤升级为int,而float升级为double。请注意,您只有格式说明符
%f
%Lf
,而对
float
则没有格式说明符。C和C++之间可能有细微的差别,但我现在还不确定,我必须检查一下。“……系统将参数推到栈上”。如果系统没有堆栈呢?那会发生什么?非常感谢你这很有道理。但是你说浮动被提升为双打是什么意思?这背后的逻辑是什么?在我看来,这正是我面临这个问题的原因,也就是说,如果float保持为4字节,而不是提升为8字节,那么一切都会顺利进行。在我的机器上,int和float是4字节,double是8字节。@tera:这就是没有原型的函数以及变量函数在C中的工作方式。所有较小的整数值都提升为
int
,而所有较小的浮点类型都提升为
double
。换句话说,不可能直接将
char
short
float
值传递给可变函数。每次这样做,值都会首先提升。@AndreyT
printf("size of int = %d, size of float = %d, size of double = %d\n",
    sizeof(int), sizeof(float), sizeof(double));
pointer to format string [probably 4 bytes]
x [probably 4 bytes]
x [probably 4 bytes]
f [probably 6 or 8 bytes]
f [probably 6 or 8 bytes]