Not when you are dealing with communication protocols, mapping
hardware control registers in embedded systems, etc.
For communication protocols: Even if you can arrange a struct's
layout to match the foreign format, you still need to deal with
representation. That two-byte integer: Is it big- or little-endian?
Ordinary positional binary or a Gray code? Is the low-order bit a
value, or is it parity? Layout is only one of the issues when mediating
between internal values and external forms, and "solving" them by
arranging a struct merely ignores the others. If you manage to get it
working with a particular compiler on a particular machine, and if "it
works" seduces you into thinking you've found the right approach, I
predict long-term headaches.
For memory-mapped registers: Although it's quite unlikely that
issues like endianness will arise, brand-new problems crop up. For
example, a four-byte register at 0xF00-0xF03 might do nothing at all
in response to accesses at 0xF01,0xF02,0xF03 -- it's not memory,
after all, but a little gadget somewhere that's waiting for 0xF00
to show up on the address lines. So you lay out your struct just like
the manual says: Four flag bits, four must-be-zero bits, a three-bit
command code and five bit sub-command code, and a two-byte integer for
the swizzle selector value. And then you store to the swizzle selector
(at 0xF02), and the hardware device ... ignores you. (Even worse,
maybe it ignores the two low-order address bits and treats the swizzle
selector as flags-and-commands!) The pretty layout of the struct has
not helped in the slightest; again, you need a completely different
approach.
Without the "pack" pragmas, instead of having a structure that
directly overlaps the desired memory layout, the packing/unpacking
would have to be in higher level software.
It has to be so anyhow. If not today, then tomorrow when the
long-term headaches begin to throb.
This is a much needed functionality, and I am puzzled why it never
became part of the language standard, instead of a not always
available compiler extension.
It could be made to work even on machines that have alignment
requirements for memory-resident objects. All you need to do is
fetch and store multi-byte objects one byte at a time, marshalling
them and unmarshalling them with extra instructions. You've got to
do this not only for packed structs, but for any pointer that might
point to a misaligned object somewhere -- yes, qsort() just slowed
down some more. This seems a high price to pay for functionality
which, despite your statement to the contrary, is in no way "needed."
That's my story, and I'm sticking to it.