【问题标题】:pack/unpack functions for C++C++ 的打包/解包函数
【发布时间】:2012-03-02 00:00:58
【问题描述】:

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

我需要一个实现 Python/Ruby/Perl 的 C 或 C++ 库,例如 pack/unpack 函数。有这样的图书馆吗?

编辑:因为我发送的数据很简单,所以我决定只使用memcpy、指针和hton* 函数。我是否需要以任何方式操纵char 以与平台无关的方式通过网络发送它? (char 仅用作字节,不用作字符)。

【问题讨论】:

  • 您能解释一下pack/unpack 在这些语言中的作用吗?
  • Pack 和 unpack 分别用于将变量转换为二进制字符串,反之亦然。它们对于创建数据包和二进制文件以及其他二进制交互非常有用。我提到的语言在他们的标准库中有这个功能。 C/C++ 没有。
  • 哦,嗯...仅供参考,这甚至是不可能的。这将需要大量的元编程(或 IDE 支持)来获取所有字段信息等等......我知道的唯一可以做到这一点的本地语言是 D
  • 我的意思类似于sprintf,只是说明符用于二进制数据。只是同样的巨型switch 声明。
  • 我为此写了一个小标题库:Php pack/unpack C++,以防有人正在寻找具有相似 API 的相同功能

标签: c++ serialization pack unpack


【解决方案1】:

在 C/C++ 中,您通常只需以正确的顺序编写带有各种成员的 struct(正确的打包可能需要编译器特定的编译指示),然后使用原始 fwrite/ 将其转储/读取到文件中/从文件中读取。 fread(或 read/write 处理 C++ 流时)。实际上,packunpack 就是为读取使用这种方法生成的内容而生的。

如果您需要将结果保存在缓冲区而不是文件中,那就更简单了,只需使用 memcpy 将结构复制到缓冲区即可。

如果表示必须是可移植的,那么您主要关心的是字节顺序和字段打包;第一个问题可以通过各种hton* 函数来解决,而第二个问题可以通过编译器特定的指令来解决。

特别是,许多编译器支持 #pragma pack 指令(参见 here 用于 VC++,here 用于 gcc),它允许您管理编译器可能在 struct 中插入的(不需要的)填充使其字段在方便的边界上对齐。

但是请记住,在某些架构中,如果特定类型的字段未在其自然边界上对齐,则不允许访问它们,因此在这些情况下,您可能需要手动执行 memcpys 来复制正确对齐的变量的原始字节。

【讨论】:

  • 您能详细说明#pragmas 吗?我使用 GCC。
  • @Linux_iOS.rb.cpp.c.lisp.m.sh:添加了一些关于#pragma pack的链接。
  • hton*/ntoh* 仅在主机按顺序(可能是大端或小端)和网络字节顺序(实际上是大端)之间转换。它们不提供序列化/反序列化以可移植方式存储little endian的值的方法。
  • 我为此写了一个小标题库:Php pack/unpack C++,以防有人正在寻找具有相似 API 的相同功能
【解决方案2】:

【讨论】:

    【解决方案3】:

    是:使用<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,因为该语言已经允许您访问其变量的二进制表示作为该语言的标准部分。

    【讨论】:

    • 我知道。我想要一个用于便携式表示的打包/解包,而不是本地字节操作。
    • 您保证只为可简单复制的类型返回有效对象。我敢肯定你已经知道了,但你没有说出来。
    • 这根本不是便携式的。您没有考虑初学者的字节序,当然它仅适用于 POD(普通旧数据)类型。
    • @Linux_iOS.rb.cpp.c.lisp.m.sh:那么,什么是存储浮点数的“便携式”方式?我的意思是你可以使用字节访问来实现任何你喜欢的序列化。例如,您可以使用通常的代数操作(buf[0] = n % 256; buf [1] = (n / 256) % 256; 等)读取/写入无符号整数(尽管在这种情况下您需要无符号字符。)是的,这仅适用于基本类型(甚至 POD)。跨度>
    猜你喜欢
    • 1970-01-01
    • 2011-09-22
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 2018-10-29
    相关资源
    最近更新 更多