9

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

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

C ++中的等价物是什么?

4

6 回答 6

3

You'll probably be better off in the long run using a third party library (e.g. Google Protocol Buffers), but if you insist on rolling your own, the C++ version of your example might be something like this:

#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

The corresponding 'unpack' code would look like this:

// 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);

In real life you'd probably be packing more than one value, which is easy enough to do (by making the array size larger and calling htonl() and memcpy() in a loop -- don't forget to increase memcpy()'s first argument as you go, so that your second value doesn't overwrite the first value's location in the array, and so on).

You'd also probably want to pack (aka serialize) different data types as well. uint8_t's (aka chars) and booleans are simple enough as no endian-handling is necesary for them -- you can just copy each of them into the array verbatim as a single byte. uint16_t's you can convert to big-endian via htons(), and convert back to native-endian via ntohs(). Floating point values are a bit tricky, since there is no built-in htonf(), but you can roll your own that will work on IEEE754-compliant machines:

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

.... and the corresponding ntohf() to unpack them:

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

Lastly for strings you can just add the bytes of the string to the buffer (including the NUL terminator) via memcpy:

const char * s = "hello";
int slen = strlen(s);
memcpy(myByteArray, s, slen+1);  // +1 for the NUL byte
于 2013-06-15T20:36:05.967 回答
1

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

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

于 2013-06-15T16:32:30.583 回答
0

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

于 2013-06-15T16:45:18.490 回答
0

我也在寻找同样的东西。幸运的是我找到了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() 函数可用于读取缓冲区

于 2018-03-13T11:07:12.207 回答
0

https://github.com/karkason/cppystruct

#include "cppystruct.h"

// icmp_header can be any type that supports std::size and std::data and holds bytes
auto [type, code, checksum, p_id, sequence] = pystruct::unpack(PY_STRING("bbHHh"), icmp_header);

int leet = 1337;
auto runtimePacked = pystruct::pack(PY_STRING(">2i10s"), leet, 20, "String!");
// runtimePacked is an std::array filled with "\x00\x00\x059\x00\x00\x00\x10String!\x00\x00\x00"
// The format is "compiled" and has zero overhead in runtime

constexpr auto packed = pystruct::pack(PY_STRING("<2i10s"), 10, 20, "String!");
// packed is an std::array filled with "\x00\x01\x00\x00\x10\x00\x00\x00String!\x00\x00\x00"
于 2021-08-19T09:28:17.027 回答
-2

您可以使用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"

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

于 2019-10-03T15:34:42.517 回答