Python在C ++中的struct.pack / unpack等价

时间:2013-06-15 16:31:24

标签: c++ python serialization

我在Python中使用struct.pack将数据转换为序列化字节流。

>>> import struct
>>> struct.pack('i', 1234)
'\xd2\x04\x00\x00'

C ++中的等价是什么?

5 个答案:

答案 0 :(得分:1)

没有。 C ++没有内置的序列化。

您必须将单个对象写入字节数组/向量,并注意endianness(如果您希望代码可移植)。

答案 1 :(得分:1)

从长远来看,使用第三方库(例如Google Protocol Buffers)可能会更好,但如果你坚持自己推出,你的例子的C ++版本可能是这样的:

#include <stdint.h>
#include <string.h>

int32_t myValueToPack = 1234;  // or whatever
uint8_t myByteArray[sizeof(myValueToPack)];
int32_t bigEndianValue = htonl(myValueToPack);  // convert the value to big-endian for cross-platform compatibility
memcpy(&myByteArray[0], &bigEndianValue, sizeof(bigEndianValue));
// At this point, myByteArray contains the "packed" data in network-endian (aka big-endian) format

相应的“解压缩”代码如下所示:

// Assume at this point we have the packed array myByteArray, from before
int32_t bigEndianValue;
memcpy(&bigEndianValue, &myByteArray[0], sizeof(bigEndianValue));
int32_t theUnpackedValue = ntohl(bigEndianValue);

在现实生活中你可能会打包多个值,这很容易做到(通过使数组大小更大并在循环中调用htonl()和memcpy() - 不要忘记增加memcpy()的第一个参数,所以你的第二个值不会覆盖数组中第一个值的位置,依此类推。)

您也可能想要打包(也就是序列化)不同的数据类型。 uint8_t(又名字符串)和布尔值很简单,因为它们不需要字节序处理 - 你可以将它们中的每一个作为单个字节逐字复制到数组中。 uint16_t你可以通过htons()转换为big-endian,并通过ntohs()转换回native-endian。浮点值有点棘手,因为没有内置的htonf(),但你可以自己动手,这将适用于符合IEEE754标准的机器:

uint32_t htonf(float f)
{
   uint32_t x;
   memcpy(&x, &f, sizeof(float));
   return htonl(x);
}

....和相应的ntohf()来解压缩它们:

float ntohf(uint32_t nf)
{
   float x;
   nf = ntohl(nf);
   memcpy(&x, &nf, sizeof(float));
   return x;
}

最后对于字符串,您只需通过memcpy将字符串的字节添加到缓冲区(包括NUL终止符):

const char * s = "hello";
int slen = strlen(s);
memcpy(myByteArray, s, slen+1);  // +1 for the NUL byte

答案 2 :(得分:1)

我也在寻找同样的事情。幸运的是我找到了https://github.com/mpapierski/struct

添加一些内容可以将缺少的类型添加到struct.hpp中,我认为它是迄今为止最好的。

要使用它,只需定义这样的参数

DEFINE_STRUCT(test,
    ((2, TYPE_UNSIGNED_INT))
    ((20, TYPE_CHAR))
    ((20, TYPE_CHAR))
)

刚刚调用此函数将在编译时生成

pack(unsigned int p1, unsigned int p2, const char * p3, const char * p4)

参数的数量和类型取决于您在上面定义的内容。 返回类型是char *,其中包含打包数据。 还有另一个unpack()函数可用于读取缓冲区

答案 3 :(得分:0)

您可以查看Boost.Serialization,但我怀疑您是否可以使用与Python包相同的格式。

答案 4 :(得分:-1)

您可以使用union将不同的视图显示到同一内存中。

例如:

union Pack{
   int i;
   char c[sizeof(int)];
};

Pack p = {};
p.i = 1234;
std::string packed(p.c, sizeof(int)); // "\xd2\x04\x00\0"

如其他答案所述,您必须注意字节序。