为什么 snprintf 不适用于 double 0x1p-1074 ...?

Why snprintf is not working for double 0x1p-1074 ...?

#include<stdio.h>

int main()
{
        char *nstring = NULL;
        int n = 0, i = 0;
        double value = 0x1p-1074;
        char buf[128] = {0};

        n = snprintf(buf, 128,"%.*f", 8, value);

        while(i < n) {
                printf("buf[%d] : Data [%c]\n", i, buf[i]);
                i++;
        }

        return 0;
}

这里我使用snprintf将double value = 0x1p-1074格式化为buf。但是当我执行上面的代码时,我得到:

buf[0] : Data [0]
buf[1] : Data [.]
buf[2] : Data [0]
buf[3] : Data [0]
buf[4] : Data [0]
buf[5] : Data [0]
buf[6] : Data [0]
buf[7] : Data [0]
buf[8] : Data [0]
buf[9] : Data [0]

我尝试使用 glibc 函数 fcvt_r 使用 __snprintf() 如下格式化 0x1p-1074 如下:

 n = snprintf (buf, len, "%.*" FLOAT_FMT_FLAG "f", MIN (ndigit, NDIGIT_MAX),
                  value);

谁能解释一下FLOAT_FMT_FLAG的用法?我还尝试在 glib 源 (misc/efgcvt_r.c) 中用 snprintf() 替换 __snprintf() 并添加一些 printf;给出了我预期的输出:

buf[0] : Data [4]
buf[1] : Data [.]
buf[2] : Data [9]
buf[3] : Data [4]
buf[4] : Data []
buf[5] : Data []
buf[6] : Data []
buf[7] : Data []

这是预期的输出。我可以在我的测试程序中使用 FLOAT_FMT_FLAG 吗?或者有没有其他方法可以得到与 glibc 源代码相同的输出?

0x1p-1074(IEEE-754 binary64 double 的最小可能次正规值,定义为 <float.h> 中的 DBL_TRUE_MIN)非常接近 0。使用 %f 打印会产生不带指数的十进制表示,如果您只需要 8 位小数,它们将全部为 0 并且输出符合预期 0.00000000.

您似乎假设 %ffcvt 应该产生相同的数字。这仅适用于 110 之间的数字。对于您的示例,fcvt 生成有效数字 4.94 但小数指数为 -324.

FLOAT_FMT_FLAG 是一个非标准的 GNU 扩展,用于告诉 printf 传递的浮点值是 long double。自 C99 以来,标准 C 将此标志定义为 L

如果您的目标是使用不提供它的 C 库生成 fcvt 的输出,您可以使用 %.8e 并去除指数部分。