如何在C中以十六进制字节格式打印float?

时间:2017-07-21 04:21:14

标签: c floating-point printf

我希望看到IEEE754格式表示的浮点值3.14159265。所以写了这个测试代码。

#include <stdio.h>

main()
{
int i;
float a = 3.141592654;

printf("a = %f\n", a);

// print test 1
printf("test 1 : a = %x\n", a);
printf("test 1 2nd time : a = %x\n", a);

// print test 2
char *pt = (char *)&a;
printf("test 2 :\n");
for(i=0;i<4;i++){
    printf("%x ", (char)(*pt++));
}
printf("\n");
}

当我运行它时,有几次,它显示如下:

ckim@stph45:~/test5] test
a = 3.141593
test 1 : a = e0cd2000
test 1 2nd time : a = e0cd2000
test 2 :
ffffffdb f 49 40 
ckim@stph45:~/test5] test
a = 3.141593
test 1 : a = 520db000
test 1 2nd time : a = 520db000
test 2 :
ffffffdb f 49 40 
ckim@stph45:~/test5] test
a = 3.141593
test 1 : a = 3b373000
test 1 2nd time : a = 3b373000
test 2 :
ffffffdb f 49 40 
ckim@stph45:~/test5] test
a = 3.141593
test 1 : a = 18a6d000
test 1 2nd time : a = 18a6d000
test 2 :
ffffffdb f 49 40 

第一个问题是:当使用带有%x的printf时,我希望看到40490fdb是IEEE754格式的3.14159265。但是,每次运行它时,值都会发生变化,如您所见。这有什么不对吗?也许我错过了一些非常基本的东西。

另一个问题是,当我使用字符指针并打印上面测试2中的十六进制值时,如何打印&#39; db&#39;而不是&#39; fffffdb&#39;? (该值显示符号扩展)。我想我之前已经完成了这些事情,但现在却无法记住它。 (我的机器是小端,所以首先显示LSB。)

3 个答案:

答案 0 :(得分:3)

您缺少的是如何在构成IEEE-754单精度浮点数的位上获得有效的外观,作为其在内存中的等效unsigned int表示。要做到这一点,同时避免违反严格别名规则(输入双关语指针),您可以在unionfloat之间使用unsigned(或更好{{1}对于精确的宽度类型),例如

uint32_t

使用#include <stdio.h> #include <stdint.h> #include <inttypes.h> #include <math.h> int main (void) { float pi = (float)M_PI; union { float f; uint32_t u; } f2u = { .f = pi }; printf ("pi : %f\n : 0x%" PRIx32 "\n", pi, f2u.u); return 0; } 代替unsigned并理解它可能不是所有硬件上的32位,标准的格式字符串就足够了,例如uint32_t。 (在这种情况下,您可以删除printf ("pi : %f\n : 0x%0x\n", pi, f2u.u);stdint.h的内容)

示例使用/输出

这将允许您在解释为无符号类型时获取构成浮点数的位的十六进制表示:

inttypes.h

答案 1 :(得分:2)

要明确的是,由于严格的别名规则&#34;,OP的代码没有失败。

You can use char* for aliasing instead of your system's word. The rules allow an exception for char*

代码失败,因为"%x"期望unsigned并且代码传递了float。这是未定义的行为(UB)。由于FP值有时以不同于整数的方式传递,因此这并不奇怪。

float a = 3.141592654;   
printf("test 1 : a = %x\n", a); // bad code

OP的后期代码几乎正确。只需要使用对象的大小和说明符中的hh来仅打印没有签名扩展名的值。

要打印的顺序取决于float的字节顺序。使用union仍然不是endian,因为float的结尾和int可能不同 - 尽管这种情况并不常见。

char *pt = (char *)&a;
//for(i=0;i<4;i++){
for(i=0;i<sizeof a;i++){
  //printf("%x ", (char)(*pt++));
  printf("%02hhx ", *pt++);
}

存在超过8位到char的罕见平台的其他问题。

简单的替代方法是使用"%a" @user2357112,它将以十六进制打印尾数/有效数,并以十进制幂为2打印指数。

将任何对象转换为&#34; hex&#34; string,this代码用作将任何对象转换为&#34;二进制代码的示例。字符串。

答案 2 :(得分:0)

我认为我正在寻找的答案是这样的。

float a = 3.141592654;
printf("test 1 2nd time : a = %x\n", *(unsigned int*)&a);

然后我得到

test 1 2nd time : a = 40490fdb