Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c++ Subject: Re: Union type punning in C++ Date: Mon, 13 Jan 2020 08:57:04 -0800 Organization: A noiseless patient Spider Lines: 140 Message-ID: <86v9pfguqn.fsf@linuxsc.com> References: <868sme2err.fsf@linuxsc.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="3f3153150e66f3eb10123de9932e6704"; logging-data="9004"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18mBA8TAO0qdZAr1wWmvS1c8IvLsg7ilnI=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:g9ykUVSKOIRbZdvFJoZQAhYvKQw= sha1:qSlyKt8xzZIKSvGBvM+SzYaFKUY= Xref: csiph.com comp.lang.c++:71306 "Chris M. Thomasson" writes: > On 1/12/2020 5:16 PM, James Kuyper wrote: > >> On 1/11/20 11:40 PM, Chris M. Thomasson wrote: >> >>> On 1/11/2020 7:28 AM, Tim Rentsch wrote: >>> >>>> "Chris M. Thomasson" writes: >> >> ... >> >>>>> #include >>>>> >>>>> struct base >>>>> { >>>>> int p0; >>>>> }; >>>>> >>>>> struct object_0 >>>>> { >>>>> base b; >>>>> int p0; >>>>> }; >>>>> >>>>> struct object_1 >>>>> { >>>>> base b; >>>>> int p0; >>>>> int p1; >>>>> }; >>>>> >>>>> union object >>>>> { >>>>> base b; >>>>> object_0 o0; >>>>> object_1 o1; >>>>> }; >>>>> >>>>> >>>>> int main() { >>>>> object o; >>>>> >>>>> o.b.p0 = 41; >>>>> o.o0.b.p0 += 1; >>>>> o.o1.b.p0 += 1; >>>>> >>>>> // humm >>>>> int r = o.b.p0; // ub... >>>>> >>>>> std::cout << "r = " << r << "\n"; >>>>> >>>>> return 0; >>>>> } >>>>> ___________________________ >>>>> >>>>> >>>>> Wrt POD and a common base object on each sub-object in a union, well >>>>> does it bite the dust with UB? >>>> >>>> I believe this runs afoul of the rules for common initial >>>> sequences, because type 'base' has as its first member a type >>>> that is not layout compatible with the type of the first members >>>> of object_0 and object_1. >>> >>> Everything boils down to an int. Therefore, the common initial sequence >>> is an int. It should work. Its all POD, everything has that common int, >>> even in struct base. ... >> >> In a standard-layout union with an active member (9.5) of struct type >> T1, it is permitted to read a non-static data member m of another union >> member of struct type T2 provided m is part of the common initial >> sequence of T1 and T2." (9.2p19). >> >> "The common initial sequence of two standard-layout struct (Clause 9) >> types is the longest sequence of non-static data members and bit-fields >> in declaration order, starting with the first such entity in each of the >> structs, such that corresponding entities have layout-compatible types >> and either neither entity is a bit-field or both are bit-fields with the >> same width." (9.2p16). "common initial sequence" is italicized in that >> text, an ISO convention identifying this sentence as the official >> definition of that term. Nothing in that definition allow you to match >> up o.b.p0 with o.o0.b.p0 in order to qualify as having a common initial >> sequence. It's the corresponding members that have to have >> layout-compatible types, and "struct base" and "int" don't. > > Damn. Need to think on this. what about something like: > ________________ > struct object_0 > { > int b; // common initial sequence > int p0; > }; > > struct object_1 > { > int b; // common initial sequence > int p0; > int p1; > }; > > union object > { > int b; // common initial sequence > object_0 o0; > object_1 o1; > }; > ________________ > > ? This gets rid of struct base. The 'int b;' member of the union object isn't needed. Simply do this: struct object_0 { int b; int p0; }; struct object_1 { int b; int p0; int p1; }; union object { object_0 o0; object_1 o1; }; To discriminate based on the "tag" field: object something = ...; if( something.o0.b == 0 ){ // the access to o0.b has to work ... // presumably o0 is the active member } else if( something.o1.b == 1 ){ // the access to o1.b ALSO has to work ... // presumably o1 is the active member } Does that all make sense?