Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Usage of union
Date: Wed, 20 Jan 2021 07:03:20 -0800
Organization: A noiseless patient Spider
Lines: 55
Message-ID: <86lfcnodl3.fsf@linuxsc.com>
References: <0f20fca0-ccf0-4f43-99f7-d2ed20d9f3b7n@googlegroups.com> <12db7b19-3ba3-4562-aee9-51531a52fcf3n@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="b1fd427021f152ca5ff6680f6ccee516"; logging-data="8211"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19iDIB+bEdbLMXef9KFDkFiS1q/h8uDNmY="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:Zrzh8zob3yDI3KPmsRKfN0Yjqm4= sha1:8NNoEtLGKXzAO4yN7/48amFD1jw=
Xref: csiph.com comp.lang.c:158481
Lew Pitcher writes:
> On Sun, 17 Jan 2021 08:41:29 -0800, wij wrote:
>
>> On Sunday, 17 January 2021 at 23:39:34 UTC+8,
>> james...@alumni.caltech.edu wrote:
>> ...
>>
>>> Note that, since the representation of types is not completely standard
>>> specified for any type, and is entirely implementation-defined for many
>>> types, there's virtually no portable way to take advantage of this
>>> fact.
>>> For example, there's no guarantee which bits of u16 are zeroed by
>>> execution of u8[0] = 0. It could, for instance, be only the
>>> odd-numbered bits (though that would require a VERY unusual
>>> architecture).
>>
>> Understandable. But:
>
> For context, here's the relevant part of the OP:
>
> //-----------------------------
> union {
> uint16 u16; [understood to mean uint16_t]
> uint8 u8[2]; [understood to mean uint8_t]
> float flt;
> } u;
>
> void t() {
> u.u16=0;
>
> assert(u.u8[0]==0);
>
>
>> 1. Will such a writing "assert(u.u8[0]==0);" cause UB?
>
> Yes. The prior code does not store a value in u.u8[0]; u.u8[0],
> therefore, holds an indeterminate value. [...]
This is wrong. The objects for u.u8[0] and u.u16 overlap.
After assigning to u.u16, u.u8[0] holds the first 8 bits of the
object representation of the value stored in u.u16. We know
those bits must all be zero. We also know that the abstract
value for the object representation (of u.u8[0]) of all bits
zero will be 0. Thus the access is well defined and must yield
the value 0, so the assert(u.u8[0]==0) must succeed. There is
no undefined behavior, or even the possibility of undefined
behavior. (Note the "understood to mean" annotations in the
above quoted code. Different types could mean different
conclusions.)
The above statements apply to C, but not to C++. In C++ the
rules for union members are different, and the access of u.u8[0]
is undefined behavior, because it is being accessed outside of
its lifetime.