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

时间:2012-12-24 08:19:24

标签: c++

如何将float转换为长度为4的字节数组(char *的数组)?我需要通过网络发送一些数据,tcp,并需要将float作为字节数组发送。 (我知道两位小数的精度,所以此时我在客户端乘以100并在服务器上除以100 - 基本上转换为整数然后用& 0xff<< operations查找字节。但它很丑陋,可能会在一段时间内失去精确度。

3 个答案:

答案 0 :(得分:12)

任何类型作为字节序列读取非常简单:

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 - 类型),并且明确是一个别名冲突。请注意,任何类型的二进制表示当然都是依赖于平台的,因此如果收件人具有相同的平台,则只应将其用于序列化。

答案 1 :(得分:5)

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

如果协议中的格式是IEEE(最常见的情况), 而且您不必移植到非IEEE的机器上 (Windows和大多数Unix都是IEEE大多数大型机不是), 然后你可以使用类型punning来将float转换为 a 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 );
}

用于big-endian(通常的网络订单),或者:

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

用于little-endian(由某些协议使用)。你使用哪一个 将取决于为协议定义的格式。

要从float转换为uint32_t,您必须检查自己的身份 编译器。使用memcpy是完全保证的唯一方法 标准;意图是使用 浮标上的reinterpret_cast<uint32_t&>也是如此 大多数(全部?)编译器也支持使用union

如果您还需要可移植到大型机或格式 是IEEE以外的东西,那么你需要提取 浮点数的指数,符号和尾数,并输出每个 目标格式。像下面这样的东西应该工作 在任何机器(包括大型机)上输出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位。)

答案 2 :(得分:2)

只需将数据叠加在一个区域中,即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....