Date: Wed, 06 Dec 2023 15:28:31 +0000
packed is cursed, please no. I would much rather see std::unaligned<Trivial>.
On 6 December 2023 00:44:50 GMT, Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> wrote:
>There has been talk lately on the mailing list here of tail padding in
>structs, and whether it can be either eradicated, or used for
>overlapping objects.
>
>Consider the following code:
>
> struct Monkey {
> long double a;
> int b;
> } __attribute__((packed));
>
> struct Donkey {
> long double a;
> int b;
> };
>
> int main(void)
> {
> static_assert( sizeof(Monkey) != sizeof(Donkey) );
>
> Monkey m;
>
> m.b = 6;
>
> int *p = &m.b;
>
> *p = 7;
> }
>
>When this program is compiled with GNU g++ or LLVM clang++, it gives
>the following diagnostic:
>
> warning: taking address of packed member 'b' of class
> or structure 'Monkey' may result in an unaligned pointer
> value [-Waddress-of-packed-member]
>
>I was thinking . . . If [[packed]] were ever to be standardised, then
>a 'packed struct' could behave as follows:
>(Rule 1) Assignment is achieved by 'memcpy'. For example the line "m.b
>= 6;" in the above snippet would become:
> int const six = 6;
> memcpy( &m.b, &six, sizeof m.b );
>(Rule 2) When taking the address of any member of a packed struct, you
>get a 'void*', for example:
> int *p = &m.b; /* fails to compile */
> void *p = &m.b; /* compiles okay */
>(Rule 3) You cannot bind a reference to any member of a packed struct:
> int &b = m.b; /* fails to compile */
>
>Of course you can get around Rule 2 and Rule 3 by using 'static_cast',
>for example:
> int *p = static_cast<int*>(&m.b);
> int &b = *static_cast<int*>(&m.b);
>but you only have to glance at these two lines to see that alignment
>might be an issue.
>
>An alternative to Rule No. 2 would be that you can't take the address
>of any member of a packed struct -- instead you must use
>'std::addressof_packed', so:
>
> int *p = &m.b; /* fails to compile */
> void *p = &m.b; /* fails to compile */
> int *p = std::addressof_packed(m.b); /* fails to compile */
> void *p = std::addressof_packed(m.b); /* compiles okay */
>
>Furthermore . . . maybe we can create a new type, a 'packed struct',
>from an already-defined 'unpacked struct'. So let's say we start out
>with:
>
> struct Donkey {
> long double a;
> int b;
> };
>
>And then later we do:
>
> typedef Donkey [[packed]] Monkey;
>
>or alternatively:
>
> using Monkey = [[packed]] Donkey;
>--
>Std-Proposals mailing list
>Std-Proposals_at_[hidden]
>https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
On 6 December 2023 00:44:50 GMT, Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> wrote:
>There has been talk lately on the mailing list here of tail padding in
>structs, and whether it can be either eradicated, or used for
>overlapping objects.
>
>Consider the following code:
>
> struct Monkey {
> long double a;
> int b;
> } __attribute__((packed));
>
> struct Donkey {
> long double a;
> int b;
> };
>
> int main(void)
> {
> static_assert( sizeof(Monkey) != sizeof(Donkey) );
>
> Monkey m;
>
> m.b = 6;
>
> int *p = &m.b;
>
> *p = 7;
> }
>
>When this program is compiled with GNU g++ or LLVM clang++, it gives
>the following diagnostic:
>
> warning: taking address of packed member 'b' of class
> or structure 'Monkey' may result in an unaligned pointer
> value [-Waddress-of-packed-member]
>
>I was thinking . . . If [[packed]] were ever to be standardised, then
>a 'packed struct' could behave as follows:
>(Rule 1) Assignment is achieved by 'memcpy'. For example the line "m.b
>= 6;" in the above snippet would become:
> int const six = 6;
> memcpy( &m.b, &six, sizeof m.b );
>(Rule 2) When taking the address of any member of a packed struct, you
>get a 'void*', for example:
> int *p = &m.b; /* fails to compile */
> void *p = &m.b; /* compiles okay */
>(Rule 3) You cannot bind a reference to any member of a packed struct:
> int &b = m.b; /* fails to compile */
>
>Of course you can get around Rule 2 and Rule 3 by using 'static_cast',
>for example:
> int *p = static_cast<int*>(&m.b);
> int &b = *static_cast<int*>(&m.b);
>but you only have to glance at these two lines to see that alignment
>might be an issue.
>
>An alternative to Rule No. 2 would be that you can't take the address
>of any member of a packed struct -- instead you must use
>'std::addressof_packed', so:
>
> int *p = &m.b; /* fails to compile */
> void *p = &m.b; /* fails to compile */
> int *p = std::addressof_packed(m.b); /* fails to compile */
> void *p = std::addressof_packed(m.b); /* compiles okay */
>
>Furthermore . . . maybe we can create a new type, a 'packed struct',
>from an already-defined 'unpacked struct'. So let's say we start out
>with:
>
> struct Donkey {
> long double a;
> int b;
> };
>
>And then later we do:
>
> typedef Donkey [[packed]] Monkey;
>
>or alternatively:
>
> using Monkey = [[packed]] Donkey;
>--
>Std-Proposals mailing list
>Std-Proposals_at_[hidden]
>https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2023-12-06 15:28:35