Boost logo

Boost :

Subject: Re: [boost] [Endian] Performance
From: John Filo (filo_at_[hidden])
Date: 2011-09-13 00:24:34


On 09/12/2011 12:13 PM, Giovanni Piero Deretta wrote:
> 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).

Thanks for the explanation. Your reply prompted me to do what I should
have done a long time ago; dig into this issue more so I better
understand it. I was suprised by the amount of conflicting (and just
plain wrong) information regarding how reinterpret_cast is supposed to
behave, but I think I understand it now.

Apologies for getting a bit off track re: this review, but the one thing
I don't understand from 5.2.10 of the standard:

-7- A pointer to an object can be explicitly converted to a pointer to
an object of different type. Except that converting an rvalue of type
``pointer to T1'' to the type ``pointer to T2'' (where T1 and T2 are
object types and where the alignment requirements of T2 are no stricter
than those of T1) and back to its original type yields the original
pointer value, the result of such a pointer conversion is unspecified.

The last sentence seems to contradict itself. It first says that the
following assertion will never trigger as long as T2's alignment
requirements are not stricter than T1's.

     void f(T1 *arg)
     {
         T2 *p2 = reinterpret_cast<T2*>(arg)
         T1 *p1 = reinterpret_cast<T1*>(p2);
         assert(p1 == arg);
     }

But then it goes on to say that the "conversion is unspecified". Is it
saying that even though the value assigned to p1 is specified the value
assigned to p2 is unspecified?

> 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.

Okay, that makes sense. Basically the fact that my aliased_ptr_cast
function has worked for me up until now is a fluke and I really can't
rely on it. Bummer.

> 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.

That's depressing; I've been using reinterpret_cast incorrectly for a
long time and have a lot of code I need to revisit. It does seem
strange that there is no portable way to do pointer casting.

Anyway, I think I've derailed this discussion enough. Thanks for the info.


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