如何将浮点数转换为长度为 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<uint32_t&>
也可以工作,并且
大多数(全部?)编译器也支持使用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* 数组)?的主要内容,如果未能解决你的问题,请参考以下文章