C++ Logo

std-proposals

Advanced search

Re: [std-proposals] [[packed]] std::unaligned

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sun, 10 Dec 2023 09:59:58 -0500
On Sat, Dec 9, 2023 at 7:20 PM Lénárd Szolnoki via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Sat, 2023-12-09 at 22:14 +0000, Frederick Virchanza Gotham via
> Std-Proposals wrote:
> > On Saturday, December 9, 2023, Frederick Virchanza Gotham wrote:
> > >
> > > In both of these use cases, I'd much prefer if we could do the
> > > following:
> > >
> > > struct TokenInfo {
> > > long unsigned a;
> > > char b;
> > > long unsigned c;
> > > char d;
> > > };
> > >
> > > typedef struct TokenInfo [[packed]] TicketInfo;
> > >
> > > So now 'TicketInfo' is a packed form of the 'TokenInfo' struct.
>
> An attribute is the wrong tool for this as it is ignorable. Maybe once
> metaclasses land then it could be feasible, and still a pure library
> implementation.
>

Actually, we were just arguing about this (basically because different
people have vastly different ideas of what "ignorable" was ever supposed to
mean in the first place) over in this CWG reflector thread:
https://lists.isocpp.org/core/2023/11/15103.php It turns out that struct
layout is pretty much the most implementation-defined thing in the world,
and thus "ignorable" by (some) definition — because an implementation can
just say "This attribute does nothing on my platform's ABI" and that's
okay. (MSVC does this with [[no_unique_address]]. That's extremely low QoI,
but there's nothing wrong with it from the paper standard's point of view.)
So [[packed]] — that is, standardizing the existing practice of
__attribute__((packed)) — would be totally fine.

However, I don't think Frederick has realized yet that his "packed
TokenInfo" (where the attribute cracks open the curly braces and applies
itself to all subobjects recursively) *is-not-a* kind of "TokenInfo". There
are things you can do with a "TokenInfo" which you physically cannot do
with such a "packed TokenInfo." One example is "fetch its `c` member with
an aligned load instruction" (because the packed TokenInfo's `c` is
misaligned). Another example is "evaluate `&p->c` and have it give you a
pointer of type `long unsigned*`" (because the language assumes that it's
always safe to load from a `long unsigned*` using an aligned load
instruction).
Clang and GCC just make this a warning: https://godbolt.org/z/vGGWYMq64
IIRC, Green Hills provides `__packed` as a type qualifier (like `const` and
`volatile`), where taking the address of a `__packed int pi` just gives you
a `__packed int *ppi`, and the compiler understands that loading from
`*ppi` will require a misaligned load.

I don't fully see what people are envisioning even with this
`std::unaligned<T>` syntax. I mean, you could make it work like
`std::atomic<T>`, and maybe that's good enough, and what people are
expecting —
    std::unaligned<int> ai = 0;
    int x = ai.load(); // copy out the value
but you certainly couldn't make it work like `T` itself —
    std::unaligned<int> ai = 0;
    int *p = &ai.value(); // point to the held value? no! physically
impossible!
    std::unaligned<MyTrivial> at;
    at->my_member_function(); // call a member function on the held value?
no! physically impossible!
(Did/does Green Hills allow you to write a member function `void
my_member_function() __packed { ~~~ }` receiving a __packed-qualified this
pointer? I don't recall. Probably not. But it would be consistent.)

–Arthur

Received on 2023-12-10 15:00:13