二进制到浮点数

gre*_*ian 5 c floating-point binary

我想从二进制表示中生成浮点变量,我很快就想出了以下代码:

float bintofloat(unsigned int x) {
    float *f = (float *)&x;
    return *f;
}
Run Code Online (Sandbox Code Playgroud)

然后可以按如下方式调用上述函数:

float f = bintofloat(0x3f800000);
Run Code Online (Sandbox Code Playgroud)

我只是希望得到一些关于这种方法的意见:使用指针是否是最好的方法,或者是否有更好或更简洁的方法?

不幸的是,我对类型的使用似乎造成了干扰。对此我深表歉意;为了简单起见,我选择坚持使用内置类型。但我确实认识到这是天真的,并假设sizeof(int) == sizeof(float)

同样,我的主要问题是使用指针是否是实现从二进制到浮点转换的好方法?

Gri*_*han 5

在您的代码中,在bintofloat()以下地址转换和取消引用的函数中无效:

float *f = (float *)&x;
return *f;
Run Code Online (Sandbox Code Playgroud)

这将在运行时调用未定义的行为。

EXP36-C。不要将指针转换为更严格对齐的指针类型

不要将指针值转换为比引用类型更严格对齐的指针类型。对于不同类型的对象可以采用不同的对齐方式。如果类型检查系统被显式强制转换覆盖,或者指针被转换为 void 指针(void *),然后转换为不同的类型,则对象的对齐方式可能会更改。

C 标准 6.3.2.3 第 7 段 [ISO/IEC 9899:2011] 规定:

指向对象或不完整类型的指针可以转换为指向不同对象或不完整类型的指针。如果生成的指针未针对引用类型正确对齐,则行为未定义。

如果取消引用未对齐的指针,程序可能会异常终止。在某些体系结构上,如果所涉及的类型具有不同的对齐要求,即使未取消引用该值,单独的转换也可能会导致信息丢失

在您的代码中x, unsigned int 具有与 float 类型不同的内存对齐方式。

类型转换float *f = (float *)&x;是有效的,但一般来说不是一个好主意。float类型指针应该指向float类型。当将 unsigned int* 引用为 float* 时,某些系统甚至可能会给程序带来致命的 SIGBUS,因为 float 需要更严格的地址对齐以达到 sizeof(float) 的倍数。

当您编写通用代码时,批准的分配未知类型地址的方法是使用void*,但要取消引用,您必须转换回正确的类型,因此实际上以下代码是错误的:

unsigned int x = 10U;
unsigned int *xp = &x; 
void* vp = x;
float* fp = vp;
float f = *fp;
Run Code Online (Sandbox Code Playgroud)

我引用的链接您提供了更多示例,将帮助您理解该问题。

您还应该阅读Keith Thompson的回答:What is the Difference Between float Pointer and int Pointer Address?

编辑:我认为你可以做如下的事情:

#include<stdio.h>
float bintofloat(unsigned int x) {
    union {
        unsigned int  x;
        float  f;
    } temp;
    temp.x = x;
    return temp.f;
}

int main(){
    float f = bintofloat(0x4236AE14U);
    printf ("\nf = %f ", f);
    printf ("\nf = %f \n", bintofloat(0x4287F0A4U));    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

将其用作:

$ gcc -Wall -pedantic binarytofloat.c
taxspanner@:~$ ./a.out 

f = 45.669998 
f = 67.970001 
Run Code Online (Sandbox Code Playgroud)

检查以下浮点精度 IEEE754 计算器的链接:

  1. 0x4236AE14U
  2. 0x4287F0A4U


gre*_*ian 3

我认为我应该记录我的首选答案是使用memcpy,正如@harold 在该评论中所建议的那样。不幸的是,我无法直接接受评论作为我问题的答案。

作为参考,使用的解决方案memcpy可能如下所示:

float bintofloat(uint32_t x) {
    float f = 0.0f;
    memcpy(&f, &x, sizeof(f) < sizeof(x) ? sizeof(f) : sizeof(x));
    return f;
}
Run Code Online (Sandbox Code Playgroud)

尽管该memcpy解决方案是我的首选答案,但我还想认识到,建议使用另一个不错的解决方案unionherehere