2

访问打包结构成员的正确方法是什么?

struct __attribute__ ((packed)) MyData {
    char ch;
    int i;
}
void g(int *x); // do something with x

void foo(MyData m) {
    g(&m.i);
}

void bar(MyData m) {
    int x = m.i;
    g(&x);
}

我的 IDE 为 foo 提供了警告/建议,我可能正在访问未对齐的 int 指针,这确实是这种情况。我的问题是

  • 在 foo 和 bar 之间,一种方法比另一种更好吗?
  • 访问未对齐的指针数据是否不正确,但可以使用它来初始化正确对齐的类型?(如酒吧)。
  • 我们是否应该将打包的 struct 单个成员复制到正确对齐的数据结构中,然后使用它?这意味着几乎每个打包数据结构都有一个非打包数据结构,而打包结构仍然局限于序列化层。
4

2 回答 2

2

目前,调用g可能会假设它x是对齐的。这在 x86 架构上可能没问题,但foo在 ARM 上可能会崩溃。

像 in 一样称呼它bar并不比g服用int x. 但是,这是正确的,因为编译器知道这m.i是未对齐的,因此可以生成代码来复制未对齐的 int。这确实意味着指针不能修改原始对象(除非您重新分配它)。

您还可以使用未对齐整数的类型:

typedef int __attribute__((aligned(1))) packed_int;
void g(packed_int * x); // do something with x

这可以直接称为g(&m.i). 请注意,它无法执行对齐的访问,从而导致某些平台上的速度变慢。

于 2022-02-04T04:33:07.963 回答
1

访问未对齐的指针数据是否不正确,但可以使用它来初始化正确对齐的类型?(如酒吧)。

就 C++ 语言而言,没有打包类之类的东西,也没有不正确对齐的对象之类的东西。因此,不正确对齐的指针必然是无效的。

为打包类提供语言扩展的编译器是否也扩展了语言以允许通过未对齐的指针进行访问,这取决于编译器供应商记录。该警告意味着可能不支持后一种扩展。

在 foo 和 bar 之间,一种方法比另一种更好吗?

bar,根据警告。

我们是否应该将打包的 struct 单个成员复制到正确对齐的数据结构中,然后使用它?这意味着几乎每个打包数据结构都有一个非打包数据结构,而打包结构仍然局限于序列化层。

这可能是将非标准打包类限制在序列化层中的便捷解决方案。

请注意,这不是打包结构的唯一问题。另一个问题是由于不同的字节顺序和类型大小,系统之间的序列化数据的可移植性。

序列化数据的一种可移植方法是根本不使用打包结构,而是使用显式偏移单独移动字节。

于 2022-02-04T01:33:11.253 回答