如何在表示浮点值的机器表示的字节数组中打印C99中指定的十六进制浮点常量?例如给出
union u_double
{
double dbl;
char data[sizeof(double)];
};
示例十六进制浮点常量是
形式的字符串0x1.FFFFFEp127f
可以在IBM site上找到此文字形式的语法规范,GCC site上有语法的简要说明。
printf函数可用于在可访问标准库中的C99功能的平台上执行此操作,但我希望能够使用标准C89或C +在不支持C99的MSVC中执行打印98。
答案 0 :(得分:4)
printf手册说:
一,A
(C99;不在SUSv2中)对于转换,double参数在样式[ - ]0xh.hhhhp d中转换为十六进制表示法(使用字母abcdef);对于A转换,使用前缀0X,字母ABCDEF和指数分隔符P.小数点前有一个十六进制数字,后面的位数等于精度。如果存在基数2中的精确表示,则默认精度足以精确表示值,否则足够大以区分double类型的值。小数点前的数字未指定非标准化数字,非零,但未指定标准化数字。
答案 1 :(得分:1)
你可以使用math.h中的frexp(),至少从C90开始,然后自己进行转换。像这样的东西(没有经过测试,没有设计用于处理像NaN,无穷大,缓冲限制等界限)
void hexfloat(double d, char* ptr)
{
double fract;
int exp = 0;
if (d < 0) {
*ptr++ = '-';
d = -d;
}
fract = frexp(d, &exp);
if (fract == 0.0) {
strcpy(ptr, "0x0.0");
} else {
fract *= 2.0;
--exp;
*ptr++ = '0';
*ptr++ = 'x';
*ptr++ = '1';
fract -= 1.0;
fract *= 16.0;
*ptr++ = '.';
do {
char const hexdigits[] = "0123456789ABCDEF";
*ptr++ = hexdigits[(int)fract]; // truncate
fract -= (int)fract;
fract *= 16;
} while (fract != 0.0);
if (exp != 0) {
sprintf(ptr, "p%d", exp);
} else {
*ptr++ = '\0';
}
}
}
答案 2 :(得分:0)
#include <stdint.h>
#include <stdio.h>
int main(void)
{
union { double d; uint64_t u; } value;
value.d = -1.234e-5;
// see http://en.wikipedia.org/wiki/Double_precision
_Bool sign_bit = value.u >> 63;
uint16_t exp_bits = (value.u >> 52) & 0x7FF;
uint64_t frac_bits = value.u & 0xFFFFFFFFFFFFFull;
if(exp_bits == 0)
{
if(frac_bits == 0)
printf("%s0x0p+0\n", sign_bit ? "-" : "");
else puts("subnormal, too lazy to parse");
}
else if(exp_bits == 0x7FF)
puts("infinity or nan, too lazy to parse");
else printf("%s0x1.%llxp%+i\n",
sign_bit ? "-" : "",
(unsigned long long)frac_bits,
(int)exp_bits - 1023);
// check against libc implementation
printf("%a\n", value.d);
}
答案 3 :(得分:0)
这可能是一个“开箱即用”的答案,但为什么不使用sprintf将double转换为字符串,然后解析字符串中的尾数和指数,将它们转换为
例如,像:char str[256];
long long a, b, c;
sprintf(str, "%e", dbl);
sscanf(str, "%d.%de%d", &a, &b, &c);
printf("0x%x.%xp%x", a, b, c);
我确定你必须修改sprintf和sscanf的格式。你永远不会得到A和F之间的第一个十六进制数字。但总的来说,我认为这个想法应该有效。这很简单。
更好的方法是找到一个为printf实现这种格式的开源库(例如,newlib,uClibc?)并复制它们的功能。