C++的打包/解包函数

4

注意: 我知道这个问题已经被问了很多次,但是没有一个问题有一个指向具体、可移植、维护的库的链接。

我需要一个实现 Python/Ruby/Perl 类似的 pack/unpack 函数的 C 或 C++ 库。这样的库是否存在?

编辑: 因为我发送的数据很简单,所以我决定只使用 memcpy、指针和 hton* 函数。我需要以平台无关的方式操作字符以便将其发送到网络上吗?(该 char 仅用作字节而非字符。)


1
你能解释一下在这些编程语言中 pack/unpack 是什么意思吗? - user541686
Pack和unpack分别用于将变量转换为二进制字符串及其反向操作。它们非常有用,可用于创建数据包、二进制文件以及其他二进制交互。我提到的语言都在其标准库中具有此功能,但C/C++没有。 - Linuxios
哦,嗯...顺便说一下,这可能甚至不可能实现。它需要大量的元编程(或IDE支持)来获取所有字段信息等...我知道唯一可能做到这一点的本地语言是D - user541686
我的意思是类似于sprintf的东西,只不过格式说明符是用于二进制数据的。就像一个巨大的switch语句一样。 - Linuxios
我为此编写了一个小型的头文件库:[Php pack/unpack C++](https://dev59.com/O0zSa4cB1Zd3GeqPqNkI#62194081),以防有人正在寻找具有类似API的相同功能。 - Waqar
3个回答

6
在C/C++中,通常你只需要按照正确的顺序(正确的打包可能需要特定于编译器的pragma)编写一个struct,并使用原始的fwrite/fread(或read/write处理C++流)将其转储/从文件中读取。实际上,packunpack是为了读取使用此方法生成的内容而产生的。
如果你需要在缓冲区中而不是文件中获取结果,那么就更容易了,只需使用memcpy将结构复制到缓冲区中。
如果表示必须是可移植的,则你的主要问题是字节顺序和字段打包;第一个问题可以通过各种hton*函数解决,而第二个问题可以通过特定于编译器的指令解决。
特别是,许多编译器支持#pragma pack指令(有关VC++的请参见此处,有关gcc的请参见此处),它允许您管理编译器可能在struct中插入的(不必要的)填充,以便将其字段对齐到方便的边界。
但是,请记住,在某些体系结构上,如果特定类型的字段未对齐到其自然边界,则不允许访问这些字段,因此在这些情况下,您可能需要执行一些手动的memcpy操作,将原始字节复制到正确对齐的变量中。

你能详细说明一下#pragma吗?我使用的是GCC。 - Linuxios
@Linux_iOS.rb.cpp.c.lisp.m.sh:添加了一些关于#pragma pack的链接。 - Matteo Italia
hton*/ntoh* 只在主机字节序(可能是大端或小端)和网络字节序(实际上是大端)之间进行转换。它们不能以可移植的方式提供序列化/反序列化存储为小端的值的方法。 - fuzzyTew
我为此编写了一个小型的头文件库:[Php pack/unpack C++](https://dev59.com/O0zSa4cB1Zd3GeqPqNkI#62194081),以防有人正在寻找具有类似API的相同功能。 - Waqar


2

是的:使用来自<algorithm>std::copy操作变量的字节表示。每个变量T x;可以通过char * p = reinterpret_cast<char*>(&x)作为字节数组访问;并且p可以像指向数组char[sizeof(T)]的第一个元素的指针一样处理。例如:

char buf[100];
double q = get_value();

char const * const p = reinterpret_cast<char const *>(&q);
std::copy(p, p + sizeof(double), buf);

// more stuff like that

some_stream.write(buf) //... etc.

返回上一页:

double r;

std::copy(data, data + sizeof(double), reinterpret_cast<char *>(&r));

简而言之,在C++中,您不需要专门的pack/unpack函数,因为该语言已经将其变量的二进制表示作为语言的标准部分开放给您。

2
我知道。我想要一个用于便携式表示的打包/解包,而不是本地字节操作。 - Linuxios
1
你只有在使用可以被平凡复制的类型时才能确保获得一个有效的对象。我相信你已经知道这一点,但你没有说出来。 - bames53
这根本不具备可移植性。首先,您没有考虑字节序,当然它只适用于POD(普通旧数据)类型。 - Correa
@Linux_iOS.rb.cpp.c.lisp.m.sh: 那么,存储浮点数的“可移植”方法是什么?我的意思是,您可以使用字节访问来实现任何喜欢的序列化方式。例如,您可以使用通常的代数操作(buf [0] = n%256; buf [1] =(n / 256)%256;等)读取/写入无符号整数。(在这种情况下,您需要无符号字符。)是的,这仅适用于基本类型(甚至不是POD)。 - Kerrek SB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接