将
%a
说明符与 printf
系列函数一起使用时,浮点数和双精度数的最长可能字符串是多少?
假设 float 和 double 是 IEEE-754 32 位和 64 位浮点数。
更具体地说,对于以下函数,
buf
需要多大才能使buf
不会溢出(注意sprintf
也会写一个空终止符):
#include <stdio.h>
void StringFromFloat(char *buf, float f) {
sprintf(buf, "%a", f);
}
void StringFromDouble(char *buf, double d) {
sprintf(buf, "%a", d);
}
我假设
%A
的最大长度没有差异。
int main() {
int c;
printf("%a%n\n", -M_PI, &c);
printf("%d\n", c+1);
printf("%a%n\n", -DBL_MAX, &c);
printf("%d\n", c+1);
printf("%a%n\n", -DBL_MIN, &c);
printf("%d\n", c+1);
}
发射
-0x1.921fb54442d18p+1
22
-0x1.fffffffffffffp+1023
25
-0x1p-1022
11
https://coliru.stacked-crooked.com/a/9c8e5f7a059b66a5
如果我们假设格式是标准的,并且双字节是 IEEE-754 64 位,那么答案似乎是 26 的长度(包括尾随的空值)
IEEE-754 64 位类型使用一个符号位(1 个字符)、一个 52 位尾数(13 个十六进制字符)和一个 11 位指数(5 个十六进制字符)。这符合我们上面的结果(
-
、fffffffffffff
和 +1023
),这意味着其他 6 个字节是〜标准格式(0x1.
、p
和'\0'
)
最长的字符串是什么
通常这是 length 所需的缓冲区 size 比长度多 1.
"%a"
有各种实现定义的细节。
合理估计:总和:
最长的有效数字长度,可能是 -1.xxx...xxx 的形式,其中 x 是十六进制数字。假设
FLT_RADIX==2
:1 /* sign */ + 2 /* 0x */ + 1 /* lead digit */ + 1 /* . */ + roundup((xxx_MANT_DIG-1)/4)
.
最长的指数,它是值
xxx_TRUE_MIN
或 1 /* p */ + 1 /* sign */ + roundup(log2(-xxx_MIN_EXP + xxx_MANT_DIG))
的 2 的十进制次方。
通常通过
snprinf(NULL, 0, "%a", -xxx_TRUE_MIN)
找到最大长度,但这并不总是正确的。
double
:
significand length: `1 + 2 + 1 + 1 + ru((53-1)/4)` --> 18
exponent length: `1 + 1 + ru(log10(- -1021 + 53))` --> 6
sum: 24
float
:
significand length: `1 + 2 + 1 + 1 + ru((24-1)/4)` --> 11
exponent length: `1 + 1 + ru(log10(- -125 + 24))` --> 5
sum: 16
考虑 NAN 的有效载荷可能以某种有趣的方式格式化,可能超过上述总和。我还没有遇到过。