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?