如何正确访问打包的结构成员

How to properly access packed struct members

访问压缩结构成员的正确方法是什么?

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 提供 warning/suggestion 我可能正在访问未对齐的 int 指针,这确实是这种情况。我的问题是

Is it incorrect to access misaligned pointer data but okay to use it to initialize a properly aligned type? (as in bar).

就 C++ 语言而言,不存在压缩 class 之类的东西,也不存在未正确对齐的对象之类的东西。因此,未正确对齐的指针必然是无效的。

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

Between foo and bar, is one approach better than the other?

bar,根据警告。

Should we copy packed struct individual members to properly aligned data structure and then use it? That would imply that for almost every packed data structure there is a non-packed data structure and packed structure remains confined to serialization layer.

这可能是一个方便的解决方案,可以将 non-standard 打包的 classes 限制在序列化层中。

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

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

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

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)。请注意,它无法执行对齐访问,从而导致某些平台速度变慢。