使用printf打印浮点值

时间:2021-11-09 20:46:11
#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;
}

The output for ff = %f is not expected.

不期望ff = %f的输出。

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

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

The point of the this code is to show what would happen if a floating value is printed with %d and if a int value is printed %f.

这段代码的重点是显示如果一个浮动值以%d打印,如果一个int值被打印%f会发生什么。

Why is the float value not being printed properly even if i use %f ?

为什么即使我使用%f,浮动值也没有被正确打印?

3 个解决方案

#1


15  

printf() is not typesafe.

printf()不是类型安全。

The arguments that you pass to printf() are treated according to what you promise the compiler.

传递给printf()的参数是根据您向编译器承诺的内容来处理的。

Also, floats are promoted to doubles when passed through variadic arguments.

此外,当通过可变参数传递浮点数时,浮点数被提升为双精度浮点数。

So when you promise the compiler %f the first time (for xf), the compiler gobbles up an entire double (usually 8 byte) from the arguments, swallowing your float in the process. Then the second %f cuts right into the zero mantissa of the second double.

因此,当您第一次向编译器保证%f时(对于xf),编译器会从参数中吸收一个完整的双字节(通常是8字节),吞噬进程中的浮点数。然后第二个%f切到第二个双精度浮点数的零尾数。

Here's a picture of your arguments:

这是你的论据:

+-0-1-2-3-+-0-1-2-3-+-0-1-2-3-4-5-6-7-+-0-1-2-3-4-5-6-7-+
|    x    |    x    |        f        |        f        |
+---------+---------+-----------------+-----------------+

%d--------|%f----------------|%f---------------|%d------|

But f looks like this (having been promoted to double):

但是f看起来是这样的(被提升为双倍):

f = 3FF8000000000000

Let's draw it again with values, and speculating about your machine endianness:

让我们再画一次,用价值,和推测你的机器机缘巧合:

| 05000000 | 05000000 | 00000000 0000F83F | 00000000 0000F83F |
| %d, OK   | %f, denormal...    | %f, denormal...   | %d, OK  |

Note that 1073217536 is 0x3FF80000.

注意,1073217536是0x3FF80000。

#2


3  

Once you pass at least one invalid format specifier to printf (like attempt to print a float value with %d or an int value with %f) your entire program gets screwed up beyond repair. The consequences of such destructive action can be seen anywhere in the program. In your case an attempt to print something with an invalid format specifier resulted in that even the valid format specifiers stopped working.

一旦您向printf传递了至少一个无效的格式说明符(例如尝试打印一个带有%d的浮点值或一个带有%f的int值),您的整个程序就无法修复了。这种破坏性行为的后果在该计划的任何地方都可以看到。在您的示例中,尝试打印带有无效格式说明符的内容会导致即使有效格式说明符也停止工作。

Speaking formally, you wrote a program that exhibits undefined behavior. It can act absolutely unpredictably. You said it yourself

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

The point of the this code is to show what would happen if a floating value is printed with %d and if a int value is printed %f.

这段代码的重点是显示如果一个浮动值以%d打印,如果一个int值被打印%f会发生什么。

The broken behavior that you observe demonstrates exactly that! A bizarrely and unpredictably acting program is exactly what happens when you attempt to do something like that.

你观察到的坏行为恰恰证明了这一点!当你试图做这样的事情时,会发生一种奇怪而不可预测的行为。

#3


0  

Try this:

试试这个:

printf("size of int = %d, size of float = %d, size of double = %d\n",
    sizeof(int), sizeof(float), sizeof(double));

When you call printf(), the system pushes the arguments onto the stack. So the stack looks something like this:

当您调用printf()时,系统将参数推入堆栈。堆栈看起来是这样的

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]

Then printf() pops bytes off the stack as it parses the format string. When it sees %d it pops enough bytes for an int, and when it sees %f it pops enough bytes for a float. (Actually, floats are promoted to doubles when they're passed as function arguments, but the important idea is that they require more bytes than ints.) So if you "lie" about the arguments it will pop the wrong number of bytes and blindly convert them according to your instructions.

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

So it will first pop the correct number of bytes for xd because you've correctly told it that x is an int.

它首先会弹出正确的xd字节数因为你已经正确地告诉它x是int型的。

But then it will pop enough bytes for a float, which will consume the second x and part of the first f from the stack, and interpret them as a float for xf.

但是,它将为一个浮点数提供足够的字节,这将消耗第二个x和第一个f的一部分,并将它们解释为xf的浮点数。

Then it will pop off enough bytes for another float, which will consume the remainder of the first f and part of the second f, and interpret them as a float for ff.

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

Finally, it will pop off enough bytes for an int, which will consume the remainder of the second f, and interpret them as an int for fd.

最后,它将为int提供足够的字节,它将消耗第二个f的剩余部分,并将它们解释为fd的int类型。

Hope that helps.

希望有帮助。

#1


15  

printf() is not typesafe.

printf()不是类型安全。

The arguments that you pass to printf() are treated according to what you promise the compiler.

传递给printf()的参数是根据您向编译器承诺的内容来处理的。

Also, floats are promoted to doubles when passed through variadic arguments.

此外,当通过可变参数传递浮点数时,浮点数被提升为双精度浮点数。

So when you promise the compiler %f the first time (for xf), the compiler gobbles up an entire double (usually 8 byte) from the arguments, swallowing your float in the process. Then the second %f cuts right into the zero mantissa of the second double.

因此,当您第一次向编译器保证%f时(对于xf),编译器会从参数中吸收一个完整的双字节(通常是8字节),吞噬进程中的浮点数。然后第二个%f切到第二个双精度浮点数的零尾数。

Here's a picture of your arguments:

这是你的论据:

+-0-1-2-3-+-0-1-2-3-+-0-1-2-3-4-5-6-7-+-0-1-2-3-4-5-6-7-+
|    x    |    x    |        f        |        f        |
+---------+---------+-----------------+-----------------+

%d--------|%f----------------|%f---------------|%d------|

But f looks like this (having been promoted to double):

但是f看起来是这样的(被提升为双倍):

f = 3FF8000000000000

Let's draw it again with values, and speculating about your machine endianness:

让我们再画一次,用价值,和推测你的机器机缘巧合:

| 05000000 | 05000000 | 00000000 0000F83F | 00000000 0000F83F |
| %d, OK   | %f, denormal...    | %f, denormal...   | %d, OK  |

Note that 1073217536 is 0x3FF80000.

注意,1073217536是0x3FF80000。

#2


3  

Once you pass at least one invalid format specifier to printf (like attempt to print a float value with %d or an int value with %f) your entire program gets screwed up beyond repair. The consequences of such destructive action can be seen anywhere in the program. In your case an attempt to print something with an invalid format specifier resulted in that even the valid format specifiers stopped working.

一旦您向printf传递了至少一个无效的格式说明符(例如尝试打印一个带有%d的浮点值或一个带有%f的int值),您的整个程序就无法修复了。这种破坏性行为的后果在该计划的任何地方都可以看到。在您的示例中,尝试打印带有无效格式说明符的内容会导致即使有效格式说明符也停止工作。

Speaking formally, you wrote a program that exhibits undefined behavior. It can act absolutely unpredictably. You said it yourself

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

The point of the this code is to show what would happen if a floating value is printed with %d and if a int value is printed %f.

这段代码的重点是显示如果一个浮动值以%d打印,如果一个int值被打印%f会发生什么。

The broken behavior that you observe demonstrates exactly that! A bizarrely and unpredictably acting program is exactly what happens when you attempt to do something like that.

你观察到的坏行为恰恰证明了这一点!当你试图做这样的事情时,会发生一种奇怪而不可预测的行为。

#3


0  

Try this:

试试这个:

printf("size of int = %d, size of float = %d, size of double = %d\n",
    sizeof(int), sizeof(float), sizeof(double));

When you call printf(), the system pushes the arguments onto the stack. So the stack looks something like this:

当您调用printf()时,系统将参数推入堆栈。堆栈看起来是这样的

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]

Then printf() pops bytes off the stack as it parses the format string. When it sees %d it pops enough bytes for an int, and when it sees %f it pops enough bytes for a float. (Actually, floats are promoted to doubles when they're passed as function arguments, but the important idea is that they require more bytes than ints.) So if you "lie" about the arguments it will pop the wrong number of bytes and blindly convert them according to your instructions.

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

So it will first pop the correct number of bytes for xd because you've correctly told it that x is an int.

它首先会弹出正确的xd字节数因为你已经正确地告诉它x是int型的。

But then it will pop enough bytes for a float, which will consume the second x and part of the first f from the stack, and interpret them as a float for xf.

但是,它将为一个浮点数提供足够的字节,这将消耗第二个x和第一个f的一部分,并将它们解释为xf的浮点数。

Then it will pop off enough bytes for another float, which will consume the remainder of the first f and part of the second f, and interpret them as a float for ff.

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

Finally, it will pop off enough bytes for an int, which will consume the remainder of the second f, and interpret them as an int for fd.

最后,它将为int提供足够的字节,它将消耗第二个f的剩余部分,并将它们解释为fd的int类型。

Hope that helps.

希望有帮助。