
On Fri, Sep 9, 2011 at 8:14 PM, john filo <filo@arlut.utexas.edu> 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