如何将浮点数转换为长度为 4 的字节数组(char* 数组)?

Posted

技术标签:

【中文标题】如何将浮点数转换为长度为 4 的字节数组(char* 数组)?【英文标题】:How to convert float to byte array of length 4 (array of char*)? 【发布时间】:2012-12-24 08:19:24 【问题描述】:

我需要通过网络发送一些数据,tcp,并且需要将浮点数作为字节数组发送。 (我知道两位小数的精度,所以目前我在客户端乘以 100,在服务器上除以 100 - 基本上转换为整数,然后使用 & 0xff

【问题讨论】:

我认为你需要 8 个字节来保持精度。 @HennoBrandsma 通常是double。在大多数现代系统上,float 是 4 字节 IEEE-754 格式。 除非您将客户端/服务器限制为一种格式(大或小),否则不要在最终解决方案中打折字节序记帐。 【参考方案1】:

any 类型读取为字节序列非常简单:

float f = 0.5f;

unsigned char const * p = reinterpret_cast<unsigned char const *>(&f);

for (std::size_t i = 0; i != sizeof(float); ++i)

    std::printf("The byte #%zu is 0x%02X\n", i, p[i]);

写入来自网络流的浮点数的工作方式类似,只是你会省略const

总是允许将任何对象重新解释为字节序列(任何char-type 都是允许的),这明确不是违反别名。请注意,任何类型的二进制表示当然是依赖于平台的,因此如果接收方具有相同的平台,则应仅将其用于序列化。

【讨论】:

但是,如果他必须向网络写入字节,这当然对他没有帮助。 @JamesKanze:当然,您可以使用write(fd, p, sizeof(float))...问题是谁能阅读 :-) 几乎没有write 是正确的情况。但问题是通过网络输出。所以他写的内容必须与他使用的协议定义的格式相对应。【参考方案2】:

您要做的第一件事是确定文件的格式 浮动在网络协议中。只知道它是4个字节 没有告诉你太多:IBM 大型机、Oracle Sparc 和通常的 PC 都有四个字节的浮点数,但它们有三个不同的 格式。一旦你知道格式,取决于它和你的 可移植性要求,可以使用两种不同的策略:

如果协议中的格式是 IEEE(最常见的情况), 而且您不必移植到非 IEEE 的机器上 (Windows 和大多数 Unix 是 IEEE——大多数大型机不是), 然后您可以使用类型双关将浮点数转换为 uint32_t,并使用以下任一方式输出:

std::ostream&
output32BitUInt( std::ostream& dest, uint32_t value )

    dest.put( (value >> 24) & 0xFF );
    dest.put( (value >> 16) & 0xFF );
    dest.put( (value >>  8) & 0xFF );
    dest.put( (value      ) & 0xFF );

对于大端(通常的网络顺序),或者:

std::ostream&
output32BitUInt( std::ostream& dest, uint32_t value )

    dest.put( (value      ) & 0xFF );
    dest.put( (value >>  8) & 0xFF );
    dest.put( (value >> 16) & 0xFF );
    dest.put( (value >> 24) & 0xFF );

用于小端(某些协议使用)。你用哪一个 将取决于为协议定义的格式。

要从 float 转换为 uint32_t,您必须检查您的 编译器。使用memcpy 是完全保证的唯一方法 标准;目的是使用 浮动上的reinterpret_cast&lt;uint32_t&amp;&gt; 也可以工作,并且 大多数(全部?)编译器也支持使用union

如果您还需要移植到大型机,或者格式 是 IEEE 以外的东西,那么你需要提取 浮点数中的指数、符号和尾数,并分别输出 目标格式。像下面这样的东西应该可以工作 在 any 机器(包括大型机)上输出 IEEE big-endian 不使用IEEE),应该给你一些想法:

oxdrstream&
oxdrstream::operator<<(
    float               source )

    BytePutter          dest( *this ) ;
    bool                isNeg = source < 0 ;
    if ( isNeg ) 
        source = - source ;
    
    int                 exp ;
    if ( source == 0.0 ) 
        exp = 0 ;
     else 
        source = ldexp( frexp( source, &exp ), 24 ) ;
        exp += 126 ;
    
    uint32_t               mant = source ;
    dest.put( (isNeg ? 0x80 : 0x00) | exp >> 1 ) ;
    dest.put( ((exp << 7) & 0x80) | ((mant >> 16) & 0x7F) ) ;
    dest.put( mant >> 8 ) ;
    dest.put( mant      ) ;
    return *this ;

(BytePutter 是一个简单的类,它处理通常的 样板文件并进行错误检查。)当然,各种 如果输出的操作将有所不同 格式不是IEEE,但这应该显示基本原则。 (如果您需要移植到一些更奇特的大型机, 不支持uint32_t,你可以用任何替换它 大于 23 位的无符号整数类型。)

【讨论】:

【参考方案3】:

只需将数据覆盖在一个区域中,在 C 中

union dataUnion   
    float f;  
    char fBuff[sizeof(float)];  
  
// to use:  
dataUnion myUnion;  
//  
myUnion.f = 3.24;  
for(int i=0;i<sizeof(float);i++)  
    fputc(myUnion.fbuff[i],fp); // or what ever stream output....  

【讨论】:

以上是关于如何将浮点数转换为长度为 4 的字节数组(char* 数组)?的主要内容,如果未能解决你的问题,请参考以下文章

将浮点数转换为字符串

将浮点数转换为字符串[重复]

如何在不进行任何舍入的情况下将浮点数转换为小数点后 4 位?

如何将浮点数保存为 2 个字节?

Abplc浮点数怎么传给4个字节

将浮点数与数组中的值进行比较时,“TypeError:只能将整数标量数组转换为标量索引”