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