如何将float转换为长度为4的字节数组(char*的数组)?我需要通过网络发送一些数据,tcp,并需要将float作为字节数组发送.(我知道两位小数的精度,所以目前我在客户端乘以100并在服务器上除以100 - 基本上转换为整数然后用&0xff <<操作查找字节).但它很丑陋,可能会在一段时间内失去精确度.
Ker*_* SB 13
将任何类型作为字节序列读取非常简单:
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]);
}
Run Code Online (Sandbox Code Playgroud)
从网络流写入浮点数的工作方式与此类似,只有您忽略了const.
始终允许将任何对象重新解释为字节序列(char允许任何类型),这显然不是别名违规.请注意,任何类型的二进制表示当然都是依赖于平台的,因此如果收件人具有相同的平台,则只应将其用于序列化.
您要做的第一件事是确定网络协议中浮动的格式.只知道它是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 );
}
Run Code Online (Sandbox Code Playgroud)
对于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 );
}
Run Code Online (Sandbox Code Playgroud)
对于little-endian(由某些协议使用).您使用哪一个取决于为协议定义的格式.
要转换float为uint32_t,您必须检查您的编译器.使用memcpy是标准完全保证的唯一方法; 意图是reinterpret_cast<uint32_t&>在float上使用a 也是如此,并且大多数(所有?)编译器也支持使用a 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 ;
}
Run Code Online (Sandbox Code Playgroud)
(BytePutter是一个简单的类,负责处理通常的样板并进行错误检查.)当然,如果输出格式不是IEEE,输出的各种操作将会有所不同,但这应该显示基本原理.(如果你需要一些不支持的更具异国情调的大型机的可移植性uint32_t,你可以用任何大于23位的无符号整数类型替换它.)
小智 6
只需将数据覆盖在一个区域中,在 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....
Run Code Online (Sandbox Code Playgroud)