How to properly access packed struct members

1.3k views Asked by At

What is the correct way to access packed struct's 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);
}

My IDE gives warning/suggestion for foo that I might be accessing misaligned int pointer, which is indeed the case here. My questions are

  • Between foo and bar, is one approach better than the other?
  • Is it incorrect to access misaligned pointer data but okay to use it to initialize a properly aligned type? (as in 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.
2

There are 2 answers

2
eerorika On BEST ANSWER

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

As far as the C++ language is concerned, there is no such thing as a packed class nor such thing as improperly aligned object. Hence, an improperly aligned pointer would necessarily be invalid.

Whether your compiler that provides a language extension for packed classes also extends the language to allow access through misaligned pointers is up for your compiler vendor to document. The warning implies that latter extension might not be supported.

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

bar, as per the warning.

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.

That could be a convenient solution to confine the non-standard packed classes into the serialisation layer.

Note that this isn't the only problem with packed structs. Another problem is portability of serialised data between systems due to different byte orders and sizes of types.

A portable way to serialise data is to not use packed structs at all, but rather shift bytes individually using explicit offsets.

0
Artyer On

Currently, calling g may assume that x is aligned. This will probably be fine on x86 architectures, but foo might crash on ARM.

Calling it like in bar is not much better than g taking int x. However, it is correct, since the compiler knows that m.i is misaligned, so can generate the code to copy a misaligned int. This does mean that the pointer can't modify the original object (unless you reassign it).

You can also use the type of a misaligned integer:

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

This can be called directly as g(&m.i). Be warned that it cannot perform aligned access leading to slowdowns on some platforms.