簡體   English   中英

C++ 中 Python 的 struct.pack/unpack 等效項

[英]Python's struct.pack/unpack equivalence in C++

我在 Python 中使用了 struct.pack 將數據轉換為序列化字節 stream。

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

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

沒有一個。 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

相應的“解壓縮”代碼如下所示:

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

我也在尋找同樣的事情。 幸運的是我找到了https://github.com/mpapierski/struct

添加一些內容可以將缺少的類型添加到struct.hpp中,我認為它是目前為止最好的。

要使用它,只需定義這樣的params

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()函數可用於讀取緩沖區

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"

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

您可以使用union獲得相同 memory 的不同視圖。

例如:

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

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

正如其他答案中提到的,您必須注意字節序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM