简体   繁体   English

从字节数组打印十六进制浮点常量

[英]Printing Hex Floating Point Constants from Array of Bytes

How can a hexadecimal floating point constant, as specified in C99, be printed from a array of bytes representing the machine representation of a floating point value? 如何从表示浮点值的机器表示的字节数组中打印出C99中指定的十六进制浮点常数? eg given 例如给

union u_double
{
    double  dbl;
    char    data[sizeof(double)];
};

An example hexadecimal floating point constant is a string of the form 十六进制浮点常量的示例是以下形式的字符串

0x1.FFFFFEp127f 

A syntax specification for this form of literal can be found on the IBM site , and a brief description of the syntax is here on the GCC site . 可以在IBM网站上找到这种形式的文字的语法规范,并且在GCC站点上可以找到语法的简要说明。

The printf function can be used to do this on platforms with access to C99 features in the standard library, but I would like to be able to perform the printing in MSVC, which does not support C99, using standard C89 or C++98. 可以在可以访问标准库中C99功能的平台上使用printf函数来执行此操作,但是我希望能够使用标准C89或C ++ 98在不支持C99的MSVC中执行打印。

printf manual says: printf手册说:

a,A 一,A

(C99; not in SUSv2) For a conversion, the double argument is converted to hexadecimal notation (using the letters abcdef) in the style [-]0xh.hhhhp d; (C99;在SUSv2中不是)对于转换,将double参数转换为[-] 0xh.hhhhp.d样式的十六进制表示法(使用字母abcdef)。 for A conversion the prefix 0X, the letters ABCDEF, and the exponent separator P is used. 对于A转换,使用前缀0X,字母ABCDEF和指数分隔符P。 There is one hexadecimal digit before the decimal point, and the number of digits after it is equal to the precision. 小数点前有一个十六进制数字,其后的位数等于精度。 The default precision suffices for an exact representation of the value if an exact representation in base 2 exists and otherwise is sufficiently large to distinguish values of type double. 如果以2为底的精确表示形式存在,则默认精度足以满足该值的精确表示形式;否则,该默认精度足够大以区分double类型的值。 The digit before the decimal point is unspecified for non-normalized numbers, and non-zero but otherwise unspecified for normalized numbers. 对于未归一化的数字,未指定小数点前的数字;对于归一化数字,未指定小数点之前的数字,但未指定。

You can use frexp() which is in math.h since at least C90 and then do the conversion yourself. 至少从C90起,您可以使用math.h中的frexp(),然后自己进行转换。 Something like this (not tested, not designed to handle boundaries like NaN, infinities, buffer limits, and so on) 这样的东西(未经测试,未设计为处理诸如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';
        }
    }
}
#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);
}

This might be an "outside the box" answer, but why not convert the double to a string using sprintf, then parse the string for the mantissa and exponent, convert those to 这可能是“开箱即用”的答案,但是为什么不使用sprintf将双精度型转换为字符串,然后解析该字符串的尾数和指数,将其转换为

eg, something like: 例如,类似:

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);

I'm sure you'd have to modify the formats for sprintf and sscanf. 我确定您必须修改sprintf和sscanf的格式。 And you'd never get a first hex digit between A and F. But in general, I think this idea should work. 而且您永远都不会在A和F之间得到第一个十六进制数字。但是总的来说,我认为这个想法应该可行。 And it's simple. 而且很简单。

A better way would be to find an open source library that implements this format for printf (eg, newlib, uClibc?) and copy what they do. 更好的方法是找到一个为printf实现此格式的开源库(例如newlib,uClibc?)并复制它们的功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM