C中的数据序列化?

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和许多其他方法,但它们都不符合我的要求:

  • 简单
  • C写的

然后我决定制作自己的数据协议.我可以处理以下整数类型的表示:

  • 无符号
  • 签署一个补充
  • 签了两个补
  • 签署了标志和数量

以有效,简单和干净的方式(令人印象深刻,没有?).然而, 真正的类型现在很痛苦.

我应该如何阅读floatdouble从字节流?该标准指出,按位运算符(至少&,|,<<>>)是 只的类型,这给我留下了没有希望的.我能想到的唯一方法是:

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)

但这似乎并不高效.我也找不着的表示的描述doublefloat.在此之前应该如何进行?

Nil*_*nck 5

如果你想使用浮点数尽可能地移植你可以使用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进行除法/乘法可能会在转换期间失去一点精度,但这是一个可以接受的妥协.

  • `INT_MAX` 是实现定义的,因此依赖它进行解码是不安全的。 (2认同)