Python's struct.pack/unpack 等价性 in C++
Python's struct.pack/unpack equivalence in C++
我使用了struct。将数据转换为序列化的字节流。
>>> import struct
>>> struct.pack('i', 1234)
'xd2x04x00x00'
c++中的等价是什么?
从长远来看,使用第三方库(例如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
对应的'unpack'代码看起来像这样:
// 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()转换为大端进制,通过ntohs()转换回本机进制。浮点值有点棘手,因为没有内置的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
没有。c++没有内置序列化。
您必须将单个对象写入字节数组/向量,并且要注意字节顺序(如果您希望代码可移植)。
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 "x00x00x059x00x00x00x10String!x00x00x00"
// 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 "x00x01x00x00x10x00x00x00String!x00x00x00"
您可以查看Boost。序列化,但我怀疑你能否让它使用与Python包相同的格式。
我也在寻找同样的东西。幸运的是我找到了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()函数可以用来读取缓冲区
您可以使用union
在相同的内存中获得不同的视图。
union Pack{
int i;
char c[sizeof(int)];
};
Pack p = {};
p.i = 1234;
std::string packed(p.c, sizeof(int)); // "xd2x04x00 "
正如在其他答案中提到的,您必须注意顺序。