3

已经看过各种代码,其中一个人将数据读入 a charorvoid然后将其转换为 astruct. 示例是解析数据具有​​固定偏移量的文件格式。

例子:

struct some_format {
    char magic[4];
    uint32_t len;
    uint16_t foo;
};

struct some_format *sf = (struct some_format*) buf;

为确保这始终有效,需要struct使用__attribute__((packed)).

struct test {
    uint8_t a;
    uint8_t b;
    uint32_t c;
    uint8_t d[128];
} __attribute__((packed));

在读取大而复杂的文件格式时,这肯定会使事情变得简单得多。通常阅读媒体格式structs具有 30 多个成员等的媒体格式。

它也很容易在巨大的缓冲区中读取并转换为正确的类型,例如:

struct mother {
    uint8_t a;
    uint8_t b;
    uint32_t offset_child;
};

struct child {
     ...
}

m = (struct mother*) buf;
c = (struct child*) ((uint8_t*)buf + mother->offset_child);

或者:

read_big_buf(buf, 4096);

a = (struct a*) buf;
b = (struct b*) (buf + sizeof(struct a));
c = (struct c*) (buf + SOME_DEF);
...

将这样的结构快速写入文件也很容易。


我的问题是这种编码方式的好坏。我正在研究各种数据结构,并会使用最好的方法来处理这个问题。

  • 这是怎么做的(如:这是常见的做法。)
  • __attribute__((packed))总是安全的吗?
  • 是不是更好用sscanf 我在想什么?,谢谢@Amardeep
  • 使用强制转换和位移来启动结构的功能会更好吗?
  • 等等

到目前为止,我主要在数据信息工具中使用它。就像以文件格式(例如媒体流)列出某种类型的所有结构及其值。信息转储工具。

4

3 回答 3

4

有时就是这样做的。只要您正确使用,包装是安全的。使用 sscanf() 意味着您正在读取文本数据,这是与结构中的二进制图像不同的用例。

如果您的代码不需要跨编译器和/或平台(CPU 架构)的可移植性,并且您的编译器支持打包结构,那么这是访问序列化数据的完全合法的方式。

但是,如果您尝试在一个平台上生成数据并在另一个平台上使用它,可能会出现问题,原因如下:

  1. 主机字节顺序(小端/大端)
  2. 语言原始类型的不同大小(例如,long 可以是 32 位或 64 位)
  3. 一侧的代码更改,但另一侧没有更改。

有一些库可以简化序列化/反序列化并处理大多数这些问题。在必须跨越进程和主机的系统上,此类操作的开销更容易证明。但是,如果您的结构非常复杂,那么使用 ser/des 库可能是合理的,因为它易于维护。

于 2013-05-06T19:06:51.210 回答
1

迄今为止,我对 C 语言标准的抱怨之一是,它们对编译器必须如何布局结构和位字段施加了足够的规则,以排除可能有用的优化[例如,在具有两个整数大小的系统上,a编译器将被禁止将八个三位字段打包成三个字节],但没有提供程序员可以指定显式结构布局的任何方法。我以前经常使用字节指针从结构中读取数据,但现在我不像以前那样喜欢这种技术了。当速度不是关键时,我现在更喜欢使用家族函数,它可以使用所需的任何字节顺序将多字节类型写入多个连续的内存位置[例如void storeI32LE(uint8_t **dest, int32_t dat)int32_t readI32LE(uint8_t const **src);]。在处理器具有正确的字节顺序并且结构成员对齐或处理器支持未对齐访问的情况下,此类代码的效率不如编译器可能编写的高效,但使用此类方法的代码可以轻松移植到任何处理器,无论其原生对齐和字节顺序。

于 2013-05-06T21:50:05.493 回答
1

这是这样做的吗?

我不明白这个问题。编辑:你想知道这是否是一个常见的成语。在可以接受对 GNU 扩展的依赖的代码库中,是的,这很常用,因为它很方便。

总是__attribute__((packed))安全的?

对于这个用例,几乎可以,除非它不可用。

是不是更好用sscanf

不,不要使用scanf().

使用强制转换和位移来启动结构的功能会更好吗?

它更便携。__attribute__((packed))是一个 GNU 扩展,并不是所有的编译器都支持它(虽然我想知道除了 GCC 和 Clang 之外还有谁关心编译器,但从理论上讲,这仍然是一个问题)。

于 2013-05-06T18:55:39.277 回答