Boost logo

Boost :

Subject: Re: [boost] [Endian] Performance
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2011-09-12 13:13:02


On Fri, Sep 9, 2011 at 8:14 PM, john filo <filo_at_[hidden]> wrote:
> I don't fully grasp the C++ aliaising rules, but Matt claims the above
> reinterpret_cast can (or does) result in undefined behavior.  In this
> particular case, gcc doesn't complain about any aliasing problems and it
> does produce the correct answer, but that doesn't mean my code is correct.

The rule itself is relatively simple (but variously interpreted): it
is UB to dereference a pointer to T if T is 'different enough' from
the actual dynamic type of the pointed memory. The definition of
'different enough' gives enough leeway to account for signed/unsigned
and, IIRC, const/non-const, but not much else (most importantly,
layout compatibility *does not* imply alias compatibility).

There are special exceptions if T is 'char': a {signed,unsigned,}
char* may alias anything, thus memcpy can be safely used to read/write
from/to pointers to arbitrary types. How to interpret the aliasing
rules when read/writing partial objects (instead of whole objects),
like fields in a structure, is anyone guess.

>
> Oddly enough, when I used a trick I've used in the past to get rid gcc
> aliasing warnings, gcc started complaining the I had aliasing problems in
> some cases, so clearly I *really* don't understand the aliasing rules in
> C++.  The trick I used is to use a union, which I though was the recommended
> way to alias a chunk of memory to multiple types.  I.e.
>
>    template<typename DST, typename SRC>
>    DST aliased_ptr_cast(DST dst)
>    {
>        union {
>            SRC src;
>            DST dst;
>        } u;
>        u.src = src;
>        return u.dst;
>    }
>
> inline uint32_t byteswap_big(uint32_t src)
>    {
>        return *aliased_ptr_cast<const ubig32_t*>(&src);
>    }
>

The union trick [1] can be used for safely bitcasting values and the
aliased_ptr_cast above will work correctly if DST and SRC are of the
same size, converting the bit representation of src from type SRC to
type DST.

If SRC and DST are pointers (as in the intended usage of the ptr
cast), it will convert a pointer type to another pointer type; this is
ok as long as the bit pattern for SRC is a valid bit pattern for DST,
but will have no effect on the pointed-to memory, so it doesn't help
in anyway to circumvent pointer aliasing.

I do not know of any portable way of safely cast pointers. GCC has
__attribute__((may_alias)), but I haven't actually tried it. A
compiler memory barrier might happen to work as aliasing UB often
manifests as unexpected read/write reordering.

HTH,

[1] The union trick has been blessed by C99 TC3 as standard
conforming, but then again, C99 and C++ rules are different enough
that probably doesn't matter.

-- 
gpd

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk