【问题标题】:The problem about printf function to "output float with %d" in C关于 printf 函数在 C 中“使用 %d 输出浮点数”的问题
【发布时间】:2021-09-25 12:14:50
【问题描述】:

我是 C 语言的新手。今天在学习浮点数的时候,发现了以下问题。

float TEST= 3.0f;
printf("%x\n",TEST);
printf("%d\n",TEST);

第一个输出:

9c9e82a0
-1667333472

第二个输出:

61ea32a0
1642738336

如上图,每次执行都会输出不同的结果。我检查了很多 IEEE 754 格式,但仍然不明白原因。想请问有没有人能解释一下或者提供关键字供我学习,谢谢。

-----------------------------------编辑----------- ------------------------------------

感谢您的回复。我知道如何打印 IEEE 754 位模式。但是,正如 Nate Eldredge chux-Reinstate Monica 所说,在 printf 中使用 %x 和 %d 是未定义的行为。如果我们的设备中没有浮点寄存器,它是如何工作的?这在 C99 规范中有描述吗?

【问题讨论】:

  • 这是 C 中未定义的行为。如果您想检查 float 的十六进制表示,您需要将 memcpy 之类的操作转换为 uint32_t
  • 特别是,在许多实现中,浮点和整数参数是在单独的寄存器中传递的,因此您在整数寄存器中打印出一些与3.0f 完全无关的值这是在一个浮点寄存器中。
  • 粉丝 Harry,使用 %g%e%a%f 打印浮点值,而不是 %x%d。后两者导致未定义的行为%a 将有助于查看 IEEE 754 格式。
  • 都错了:请尝试printf("%f\n",TEST);
  • "如果我们的设备中没有浮点寄存器,它是如何工作的?" “这在 C99 规范中有描述吗?” --> C 没有详细说明。这取决于实施。

标签: c printf ieee-754


【解决方案1】:

大多数时候,当您使用“错误种类”(错误类型)的参数调用函数时,会发生自动转换。例如,如果你写

#include <stdio.h>
#include <math.h>

printf("%f\n", sqrt(144));

这很好用。编译器(从&lt;math.h&gt; 中的函数原型)知道sqrt 函数需要double 类型的参数。您将int144 传递给它,因此编译器在将其传递给sqrt 之前自动将int 转换为double

但对于printf 函数,这不是正确的。 printf 接受许多不同类型的参数,只要每个参数都适合格式字符串中的特定 % 格式说明符,就可以了。所以如果你写

double f = 3.14;
printf("%f\n", f);

它有效。但是如果你写

printf("%d\n", f);     /* WRONG */

它不起作用。 %d 需要 int,但您传递了 double。在这种情况下(因为printf 是特殊的),编译器没有插入自动转换的好方法。因此,它只是无法正常工作。

当它“失败”时,它真的失败。你甚至不一定会得到任何“合理”的东西,比如一个表示你认为你通过的 IEEE-754 浮点数的位模式的整数。如果您想检查 floatdouble 的位模式,则必须以另一种方式进行。


如果您真正想做的查看组成float 的位和字节,这里有一种完全不同的方式:

float test = 3.14;
unsigned char *p = (unsigned char *)&test;
int i;
printf("bytes in %f:", test);
for(i = 0; i < sizeof(test); i++) printf(" %02x", p[i]);
printf("\n");

字节排序(“endianness”)存在一些问题,但这应该可以帮助您入门。

【讨论】:

    【解决方案2】:

    打印浮点数的十六进制(即它在内存中的表示方式)表示:

        float TEST= 3.0f;
        int y=0;
    
        memcpy(&y, &TEST, sizeof(y));
        printf("%x\n",y);
        printf("%d\n",y);
    

        union
        {
            float TEST;
            int   y;
        }uf = {.y = 0};
    
        uf.TEST = 3.0f;
        printf("\n%x\n",(unsigned)uf.y);
        printf("%d\n",uf.y);
    

    假设sizeof(float) &lt;= sizeof(int) 的两个示例(如果它们不相等,我需要将整数归零)

    结果(两者相同):

    40400000
    1077936128
    

    如您所见,它与您的完全不同。 https://godbolt.org/z/Kr61x6Kv3

    【讨论】:

    • 假设浮点数的大小等于或小于整数的大小。
    猜你喜欢
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多