rog*_*ogi 2 c floating-point serialization
我有这个结构,我想写一个文件:
typedef struct
{
char* egg;
unsigned long sausage;
long bacon;
double spam;
} order;
Run Code Online (Sandbox Code Playgroud)
此文件必须是二进制文件,并且必须可由任何具有C99编译器的计算机读取.
我查看了这个问题的各种方法,例如ASN.1,XDR,XML,ProtocolBuffers和许多其他方法,但它们都不符合我的要求:
然后我决定制作自己的数据协议.我可以处理以下整数类型的表示:
以有效,简单和干净的方式(令人印象深刻,没有?).然而, 真正的类型现在很痛苦.
我应该如何阅读float
和double
从字节流?该标准指出,按位运算符(至少&
,|
,<<
和>>
)是
整只的类型,这给我留下了没有希望的.我能想到的唯一方法是:
int sign;
int exponent;
unsigned long mantissa;
order my_order;
sign = read_sign();
exponent = read_exponent();
mantissa = read_mantissa();
my_order.spam = sign * mantissa * pow(10, exponent);
Run Code Online (Sandbox Code Playgroud)
但这似乎并不高效.我也找不着的表示的描述double
和float
.在此之前应该如何进行?
如果你想使用浮点数尽可能地移植你可以使用frexp和ldexp:
void WriteFloat (float number)
{
int exponent;
unsigned long mantissa;
mantissa = (unsigned int) (INT_MAX * frexp(number, &exponent);
WriteInt (exponent);
WriteUnsigned (mantissa);
}
float ReadFloat ()
{
int exponent = ReadInt();
unsigned long mantissa = ReadUnsigned();
float value = (float)mantissa / INT_MAX;
return ldexp (value, exponent);
}
Run Code Online (Sandbox Code Playgroud)
这背后的想法是,ldexp,frexp和INT_MAX是标准C.而无符号长的精度通常至少与尾数的宽度一样高(不保证,但它是一个有效的假设,我不知道这里不同的单一架构.
因此转换工作没有精度损失.使用INT_MAX进行除法/乘法可能会在转换期间失去一点精度,但这是一个可以接受的妥协.