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

C++ 如何将浮点转换为长度为4的字节数组(字符数组*)?,c++,C++,如何将浮点转换为长度为4的字节数组(字符数组*)?我需要通过网络发送一些数据,tcp,并且需要以字节数组的形式发送float。(我知道精度是两位十进制数字,所以现在客户端的I乘以100,服务器端的I除以100-基本上转换为整数,然后用&0xff查找字节,将任何类型读取为字节序列非常简单: float f = 0.5f; unsigned char const * p = reinterpret_cast<unsigned char const *>(&f); for (s

如何将浮点转换为长度为4的字节数组(字符数组*)?我需要通过网络发送一些数据,tcp,并且需要以字节数组的形式发送float。(我知道精度是两位十进制数字,所以现在客户端的I乘以100,服务器端的I除以100-基本上转换为整数,然后用&0xff查找字节,将任何类型读取为字节序列非常简单:

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]);
}
float f=0.5f;
无符号字符常量*p=重新解释强制转换(&f);
对于(std::size_t i=0;i!=sizeof(float);+i)
{
std::printf(“字节#%zu是0x%02X\n”,i,p[i]);
}
从网络流写入浮点值的工作原理与此类似,只是省略了
const


始终允许将任何对象重新解释为字节序列(允许使用任何
char
-类型),这显然不是别名冲突。请注意,任何类型的二进制表示形式当然取决于平台,因此,如果收件人具有相同的平台,则仅应将其用于序列化。

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

如果协议中的格式为IEEE(最常见的情况), 而且你不必携带到不是IEEE的机器上 (Windows和大多数Unix是IEEE,而大多数大型机不是), 然后,您可以使用类型punning将浮点转换为 a
uint32\u 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(通常的网络顺序),或:

对于little endian(某些协议使用)。您使用哪一种 将取决于为协议定义的格式

要从
float
转换为
uint32\u t
,您必须检查 编译器。使用
memcpy
是 标准;目的是使用 a
重新解释浮球工作的铸造,以及
大多数(全部?)编译器还支持使用
联合

如果您还需要移植到大型机,或者 是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 ;
}
oxdrstream&
oxdrstream::运算符1);
目的地投入((实验>16)和0x7F));
目的地投入(mant>>8);
目的地put(mant);
归还*这个;
}
BytePutter
是一个简单的类,负责处理通常的 样板文件并进行错误检查。)当然,各种 如果输出 格式不是IEEE,但应显示基本原则。 (如果您需要移植到一些更奇特的大型机, 如果不支持
uint32\u t
,则可以将其替换为任何
大于23位的无符号整数类型。)

只需将数据覆盖在一个区域中,即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....  
联合数据联合{
浮动f;
char fBuff[大小(浮动)];
}  
//使用:
数据联盟myUnion;
//  
myUnion.f=3.24;

对于(int i=0;我认为需要8个字节才能保持精度。@HennoBrandsma这通常是一种
double
。在大多数现代系统上,
float
是4字节的IEEE-754格式。在最终解决方案中,不要打折endian记帐,除非您将客户端/服务器限制为一种格式(大或小)。但是,如果他必须向网络写入字节,这当然不会真正帮助他。@JamesKanze:当然,你可以使用
write(fd,p,sizeof(float))
…问题是谁能读到:-)实际上没有任何情况下
write
是正确的。但问题是通过网络输出。因此,他写的内容必须符合他使用的协议定义的格式。
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....