Type-punning and strict-aliasing

Published Friday June 10th, 2011 | by

A couple of months ago, I posted a lengthy email to the internal discussion list about the problems with type punning and breaking of strict aliasing. At the time, my sole objective was to clean up any warnings in my build of Qt 4.7 when using GCC 4.5. Since then, GCC 4.6 was released and bug QTBUG-19736 was reported against the very same code I had been trying to clean-up.

So a colleague nudged me into posting the content of my email explaining the situation on the blog. Here it goes, with a couple of updates:

The warning from GCC reads:

“dereferencing type-punned pointer will break strict aliasing”

It’s quite scary because it says this will break stuff. So what is this?

Quoting from http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html:

One pointer aliases another when they both point to the same memory location.

Type-punning is the trick to refer to an object by another type. Strict aliasing is the requirement from C99 that an object be accessed only by its own type or by char (see the exact definition from C99 below). That means the following is not acceptable:

        int i = 42;
        short s = *(short*)&i;

The above will probably work (emphasis on probably), but the results are undefined. That means the compiler is free to do anything, like emailing your boss about this transgression. But even without the strict-aliasing rule, the code above still has no defined behaviour, as it has two possible results: 0 or 42, depending on the endianness.

And that was going to a type with less strict alignment rules. Increasing the requirement like this:

        short s[2] = { 0, 42 };
        int i = *(int *)s;

Has three possible outcomes: i == 0, i == 42 or crash (unaligned 4-byte load).

Now, it gets interesting when we put together the strict aliasing rule with optimisations. The compiler is allowed by the standard to assume that dereferencing pointers to objects of different types will never refer to the same memory location (they will not alias each other).

That means this code:

        void *buf[4];
        int *i = (int *) buf;
        short *s = (short *) buf;

        *i = 42;
        s[0] = 0;
        s[1] = 1;

        printf("%dn", *i);

is also undefined, because you broke the rule. The above can print three different things (or defrost your fridge):

    1 (big-endian architecture)
    65536 (little-endian architecture)
    42  

The reason why it can print 42 is because the compiler is allowed to assume that the short *s variable never aliases the int *i one. That means it knows *i == 42 and can optimise the short code out of existence. In fact, that’s exactly what GCC 4.5 does and the disassembly of the above code confirms it.

This also applies to the code:

        union {
                int i;
                short s;
        } u;
        u.i = 42;
        u.s = 1;

        printf("%dn", u.i);

The behaviour above is undefined according to the C standard. It is, however, accepted by GCC (it prints 1 on x86) — but not by other compilers. I refer to you to the case of c1b067ea8169e1d37e2a120334406f1f115298bb. QMutexLocker had:

    union {
        QMutex *mtx;
        quintptr val;
    };

And we did:

            if ((val & quintptr(1u)) == quintptr(1u)) {
                val &= ~quintptr(1u);
                mtx->unlock();
            }

Which was meant to be read as “if the pointer address has the lowest bit set, unset it and call mtx->unlock()“. However, this breaks the strict-aliasing rule and Sun CC generated bad — but perfectly valid — code which called QMutex::unlock() with the lowest bit still set. Of course, the code crashed.

A much harder to see case was 2c1b11f2192fd48da01a1093a7cb4a848de43c8a (task 247708, sorry, not imported into the new bugtracker), affecting QDataStream’s byte-swapping code. It did:

QDataStream &QDataStream::operator>>(qint16 &i)
{
...
        register uchar *p = (uchar *)(&i);
        char b[2];
        if (dev->read(b, 2) == 2) {
            *p++ = b[1];
            *p = b[0];
...

Looks safe, right? Well, it wasn’t and for a while I wasn’t convinced this wasn’t a compiler bug. What happened was that, due to Link Time Code Generation, MSVC inlined the operator>> above and removed the code that actually set the qint16 variable. See below the C99 definition to see why I wasn’t convinced.

Anyway, the problem is that the optimisations done by the compiler obey the strict aliasing rule, which can produce unexpected results. Take the example from this blog:

http://jeffreystedfast.blogspot.com/2010/01/weird-bugs-due-to-gcc-44-and-strict.html

The author had code he thought was valid and had been working for a long time. An upgrade to GCC 4.4 broke the code, but that’s because there was violation to strict aliasing. The line

        tail = (Node *) &list;

created a type-punned variable and its dereferencing in

        tail->next = node;

was the violation.

So you may ask why this rule is there at all. Well, the reason is that this rule is very useful for compiler optimisations, as they allow the compiler to take some liberties that it otherwise couldn’t. Take this example from the first part of the blog What Every C Programmer Should Know About Undefined Behavior:

float *P;
void zero_array() {
   int i;
   for (i = 0; i < 10000; ++i)
     P[i] = 0.0f;
}

The author of the blog tells you that

this rule allows clang to optimize this function [...] into “memset(P, 0, 40000)

and that without such liberty

Clang is required to compile this loop into 10000 4-byte stores (which is several times slower)

A bit further down and in part 3, the author explains why that is. So think about it: without strict-aliasing, why must the compiler do 10000 4-byte stores instead a simple 40000-byte memset? While you think about it, here’s the link to part 2.

The reason is that the compiler cannot assume that the value of P (a pointer type) stays unchanged while it’s storing values to each of P[i] (a float type). Someone could write the following code:

int main() {
  P = (float*)&P;
  zero_array();
}

In that case, the store to P[0] also changes the value of P, so the next operation (the storing at P[1]) must be computed at a different address.

With careful coding, it’s possible to use type-punning and not break strict aliasing. However, it’s very hard to do so and it’s also hard not to throw the compiler into a fit. So, the rule of thumb is: if you type-pun (that is, if you cast to a different pointer type via C-cast or reinterpret_cast) you should think again. If you type-pun and dereference, think again twice.

C99 6.5 7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

Did you like this? Share it:

Posted in Uncategorized

39 comments to Type-punning and strict-aliasing

illissius says:

Does this limitation also apply to void pointers? I.e. does casting a void pointer to any other type of pointer also result in undefined behaviour?

What about the explicit allowance for char? Does that mean the compiler must assume that a pointer to char could potentially alias any other pointer?

Daniel Cheng says:

@illissius, it also apply to void pointers.
For instance, you can’t do something like this:

void f(void *x) {
int *p = (int*) x;
..
}

short a[10];
f(a);

> union {
> int i;
> short s;
> } u;
> u.i = 42;
> u.s = 1;
>
> printf(“%dn”, u.i);
>
> The behaviour above is undefined according to the C standard.

No, not quite. It’s implementation defined behavior, which requires each compiler to chose and document its behavior. See section 3.3.2.3 in the C89 standard and C90 6.3.2.3.

gcc for example documents its behavior here: http://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit_002dfields-implementation.html

Thiago Macieira says:

@Henrik: implementation-defined behaviour that can vary wildly is as useful as undefined behaviour when you’re writing cross-platform code.

Yes, GCC documents “The relevant bytes of the representation of the object are treated as an object of the type used for the access”. But as my example of QMutexLocker showed, Sun CC considers that strict-alias breaking.

The union trick can be used when we know what compilers we’re using. MSVC has the same implementation as GCC for this particular. The fix for the QDataStream operator was actually to use a union and hope Sun CC won’t complain.

Michael Kreitzer says:

As far as I can tell from reading the referenced sections of the standard and from existing background knowledge on the subject I’m not so sure this represents this type of behavior as being standard. Sure, obeying strict aliasing rules can potentially help optimize poorly design C code, and for reasons beyond my comprehension GCC decided to make this flag default to on. C99 and previous versions, however, maintain the simple concept of a pointer simply being, well, a pointer. Use it as you see fit.

C99 did, however, introduce the concept of the “restrict” qualifier as a hint to compilers that this pointer will obey strict aliasing rules. This, in this commenters lowly opinion, is the much better solution and why GCC should not enable strict aliasing by default. It maintains compatibility with older C standards while still providing the option in a standard way and, most importantly, in the code itself to use strict aliasing rules where it is advantageous.

Thiago Macieira says:

@Michael: strict aliasing is a feature of the standard. The portion of the C99 spec that I quoted in the text of the blog is what defines the strict aliasing. If your code fails to comply with that requirement, you have undefined behaviour and the compiler can do anything. Really, anything: it can do what you expect, it can produce wrong results, it can crash (like clang, that likes to insert “ud2″ instructions) or it could do something completely different like send your new phone number to your ex-girlfriend’s mother.

Please read the three-parter blog that I pointed out and study the zero_array example. Pay attention to what I said and quoted: without the strict-aliasing guarantee, the compiler cannot replace the 10000 4-byte sets with one 40000-byte memset.

Also note that C++98 doesn’t have the “restrict” qualifier and C++11 doesn’t bring it either. But both have the same “strict-aliasing” requirement. Here’s the C++11 spec, from the FDIS (N3290), 3.10:

10 If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type similar (as defined in 4.4) to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
— an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.

Michael Kreitzer says:

@Thiago: The way I’m reading that is a simple requirement for defined behavior of assignments. I.e. if your assignment doesn’t follow those rules you need to cast or convert in some other way. It’s a very simple “x = y” is only defined if y is of a type similar enough to x. If it’s not, convert it somehow (including casting). I do not see any mention of doing a cast to meet those conditions being illegal nor do I see any mention of those pertaining specifically to pointers. It is my assertion that -fstrict-aliasing (the now on by default option) is not standard compliant. The compiler should assume aliasing unless the restrict qualifier is provided.

If I’m missing some context or something obvious please let me know. The C++11 standard is a testament to intentional crypticness, so lets stick to C99 to keep complexity low for the sake of discussion. I recognize C++ may be different, and, if that’s the case, I welcome references to the current draft standard that indicate this.

For C99 you want to look at 6.3.2.3 7:

“A pointer to an object or incomplete type may be converted to a pointer to a different
object or incomplete type. If the resulting pointer is not correctly aligned57) for the
pointed-to type, the behavior is undefined. Otherwise, when converted back again, the
result shall compare equal to the original pointer. When a pointer to an object is
converted to a pointer to a character type, the result points to the lowest addressed byte of
the object. Successive increments of the result, up to the size of the object, yield pointers
to the remaining bytes of the object.”

This is essentially an explicit statement saying you can cast in any way you see fit with some caveats.

In C++11 the seemingly analogue section is 4.10, and it is seemingly lacking this explicit permission to cast in this way so perhaps aliasing has been outright removed in C++ (or maybe was never allowed? I’m much more of a C user than C++). I’d love to see something clearly settling this one for good.

It does seem clear that in C99 aliasing is allowed.

lacos says:

Re: QDataStream::operator>>

(1) This is C++, so the C99 standard is not directly relevant. It’s only relevant for now where the C++ standard (98 or 03, your choice) defers to it.

(2) C++98 3.9p2 explicitly allows what QDataStream::operator>> does (assuming qint16 is a POD type taking up exactly two bytes), so that’s an MSVC bug.

Thiago Macieira says:

@Michael: casting pointers is not the issue. And clearly casting pointers in C++ is more restricted than in C due to the increased type safety. I also don’t think you got the case of zero_array: it has nothing to do with casting. The point is that an assignment of P[x] isn’t allowed to change the value of P.

Go back to the definition from the beginning of the blog: “One pointer aliases another when they both point to the same memory location.” And type punning is when you access an object via a different type than what it was declared with. GCC’s warning says that if you dereference a type-punned pointer — that is, a pointer that aliases another, but of a different type — you will break the strict aliasing rule.

The strict-aliasing rule from both C and C++ standards says that the compiler is allowed to assume that a variable of one type does not alias (meaning: does not occupy the same region in memory as) another variable with a different type, except as listed in those definitions. That’s why the compiler can replace the 10000 4-byte stores with one memset: since the stores to P[x] are of type float, the compiler can assume that no variable of type float * (like P) will be changed. Once it knows that P is constant throughout the loop, the loop is simplified to a memset

Also, please understand that the standards mandate strict-aliasing. When you say “the compiler should assume aliasing unless the restrict qualifier is provided,” you’re actually wrong: the standard says there is no aliasing of variables. The -fstrict-aliasing option is the implementation of that rule — you may argue that GCC’s implementation is broken, but you can’t argue that strict-aliasing isn’t compliant.

Finally, note the difference between this rule and restrict. This new C99 keyword is in fact an extension of the aliasing: for example, if I have char * restrict a, * restrict b then these two variables do not alias each other, even if they are of the same type. The following code has undefined behaviour:

    char buffer[100];
    char * restrict ptr1 = buffer;
    char * restrict ptr2 = buffer + 1;

    ptr2[0] = 'a';
    ptr1[1] = 'b';
    return ptr2[0];

Without the restrict keywords, this code should return ‘b’. With it, the compiler is allowed to assume that the assignment to ptr2 produces no effect on ptr1, so it can optimise out the ptr1[1] assignment as dead code and return ‘a’.

Thiago Macieira says:

@lacos: the C++98 standard also includes the strict-aliasing rule (3.10p15), with the same wording as C++11 as above.

3.9p2 is basically saying that aliasing by a character type is permitted. You’re right though: this may be a compiler bug. I said I wasn’t entirely sure.

Eric says:

I once got rid of those warnings by casting to char* then to my other type. Masks the warnings, keeps the undefined behavior. Terrible “rookie mistake”, that has fortunately not broken anything (yet).

Yuriy says:

#include
int main()
{
void *buf[4];
int *i = static_cast(buf);
short *s = static_cast(buf);

*i = 42;
s[0] = 0;
s[1] = 1;

printf(“%dn”, *i);
return 0;
}
> g++ a.cpp
a.cpp: In function ‘int main()’:
a.cpp:5:40: error: invalid static_cast from type ‘void* [4]‘ to type ‘int*’
a.cpp:6:44: error: invalid static_cast from type ‘void* [4]‘ to type ‘short int*’

You write the code on a C and try to force to work it in a C ++ is the full nonsense.

#include
#include “mainwindow.h”

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
int *i = (int *)(&w);
*i = 500;
w.show();

return a.exec();
}
Conversion usage “at any cost” your problems.

Yuriy says:

int *i = static_cast<int *>(buf);
short *s = static_cast<short *>(buf);

At pushing submit has for some reason truncated

Michael Kreitzer says:

@Thiago: Would you please help me out with understanding how the language in C99 mandates strict aliasing? C99 6.5 7 doesn’t seem to, or I’m not understanding it correctly? It does put restrictions on types for assignments, but types are easily changed with a simple cast.

Without any extra language it seems interpreting this as a mandate for strict aliasing is a bit of a stretch, and the lack of any extra language doesn’t result in any undefined behavior. That the compiler wants to optimize code is a few layers up and not the specs problem. That you can cast to comply with 6.5 7 seems possible without violating any language in the spec, and the compiler should be able to handle this case. In that case -fstrict-aliasing is more of a contract between you and the compiler that you’ll follow certain rules so the compiler can better optimize for you.

Can you recommend any further reading on analysis of this part of the spec and how it’s been interpreted to imply a mandate for strict aliasing? I’d love to read up on how this evolved. I’ve tried google, but all I can find are discussions of what strict aliasing is and how not to break it. I can find nothing on the interpretation of the spec itself.

Finally, thank you for taking the time to discuss this with me. It’s been an interesting discussion.

Thiago Macieira says:

@Michael: first, you have to take it that 6.5p7 is the definition of strict-aliasing. It defines that “An object shall have its stored value accessed only by [an] expression that has one of the following types” and basically lists the same type (unsigned or signed) and a character type. It’s very limiting: you can only access the stored value by a compatible type or by a character type.

Then let’s interpret what GCC does and complains about. First, you have an object in memory of a given type T. Then you create a pointer to it (T *) and you cast that pointer to an incompatible pointer (say, X *). At this point, the two pointers have aliasing values (they point to the same memory). Since the second pointer is pointing to an object of a different type, it is type-punned. If you dereference it, you’re accessing the stored value via an incompatible type. Hence, “dereferencing of type-punned pointer will break strict-aliasing rules”.

When you say “a contract between you and the compiler that you’ll follow certain rules so the compiler can better optimize for you,” that is a given. You’re writing code using a standardised language — that itself is the contract between you and the compiler. When you write i = 42, you mean “take the literal value of 42, perform integer casts to the appropriate type of i and store it in that memory location”. It doesn’t mean “execute a system call to format my disk”.

Undefined behaviours are left by the authors of the standard as a way to permit the compiler to have more freedom to optimise the code. I really recommend reading the three-parter blog series from LLVM/clang and this one from John Regehr’s Blog, as they explain why undefined behaviour exists.

Michael Kreitzer says:

I found something here: http://std.dkuug.dk/JTC1/SC22/WG14/www/C99RationaleV5.10.pdf

It’s discussed on page 67 where it’s clearly stated this was the intent of that section. I still find the language exceptionally vague, but such is life I suppose.

mnk says:

The controversy surrounding strict aliasing is an old topic.
See i.e. this post: http://lkml.org/lkml/2003/2/26/158

Mindset says:

I always wonder why people write code like the QMutex one. It’s developers trying to be overly clever. Very few people understand the implications of convoluted code. Why not first write basic simple code, then profile it and then make obfuscated changes. I have seen this habit quite often, where lots of optimizations (and obfuscation) happen prematurely.

Philippe says:

@Mindset: I agree with what you say in general, but not for widely used primitives, hence quoting QMutex here is wrong.

Thiago Macieira says:

@Mindset: guess what? That’s what we did. We wrote QMutex and QMutexLocker. We could easily make QMutexLocker just call QMutex::lock and unlock. But turns out that if you unlock and relock, it would be nice to avoid the function call.

So we introduced a way for QMutexLocker to track whether it had unlocked its mutex. Given BC requirements, we couldn’t add a boolean. So we just used one bit of the pointer. And it worked fine with most compilers. Just not with Sun CC.

Now it works fine with all compilers.

tr3w says:

Ok, I’m lost.
I want to use exp approximation like this: http://cnl.salk.edu/~schraudo/pubs/Schraudolph99.pdf
I didn’t like this static union thing, so first I created some pointer tricks which does the same.
As it turned out, I broke strict aliasing rules, so I got a big warning.
So I created the following implementation:
union
{
double d;
int i[2];
} temp;
temp.i[0] = 0;
temp.i[1] = static_cast<int>((1048576 / M_LN2) * y + (1072693248 – 60801));

And it’s working and I didn’t get any warning. But as I can understand now it’s broke strict aliasing rules too.

So the question is: how on earth can I do something like this???

The User says:

template inline T brutal_cast(const U& x)
{
union tmp
{
typename StripReference::Result *t;
const U *u;
inline tmp(const U* u) : u(u) {}
};
return *tmp(&x).t;
}

This casts anything without gcc-warning (unless you have an overloaded operator&). It might be useful if you do exactly know that two types have the same internal representation.

The User says:

@tr3w
That code is definitely okay, it is simply platform dependent, but you should use types ensuring the size of the types and add a static assertion for the endianness. Such unions are the prefered way for some optimisation tricks, I think.

union Float32
{
float value;
struct
{
uint32_t mant: 23;
uint32_t exp: 8;
uint32_t signbit: 1;
};
signed char exponent()
{
return exp – 127;
}
bool sign()
{
return signbit;
}
uint32_t mantisse()
{
return mant;
}
}; ;)

anttirt says:

@The User

That brutal_cast is illegal unless at least one of T or U is char, signed char or unsigned char. An example of how things might go wrong is that after inlining the compiler might reorder a store to the original memory address to go after the inlined function call, which would end up looking like your brutal_cast gives the old value of a variable.

anttirt says:

@tr3w

That doesn’t break strict aliasing rules but does have implementation-defined behavior, which might be wrong (like the problem with the Sun CC in the article.)
There’s one method to avoid that and avoid undefined behavior as well:

double d;
int i[2];
assert(sizeof(i) == sizeof(d));
i[0] = 0;
i[1] = static_cast((1048576 / M_LN2) * y + (1072693248 – 60801));
memcpy(&d, &i[0], sizeof(d));

By *only* accessing the underlying bytes (as memcpy does) you don’t break any aliasing rules.

The User says:

@anttirt
I did not say it would not be dangerous, but if you know what you are doing, you get rid of the strict-aliasing warning.

Thiago Macieira says:

The only safe way of doing those things is via memcpy.

Anonymous says:

Strict aliasing effectively lets the compiler assume a useful property without actually verifying it. How about just enhancing the compiler to verify lack of aliasing before relying on it? In the case of the array initialization that should turn into a memset, the compiler should check that the caller doesn’t do something crazy like point the array to itself. And with link-time optimization, the compiler can always have the caller’s code available for cross-procedure analysis. For library interfaces that require separate compilation, use restrict.

Benjamin Herr says:

“3.9p2 is basically saying that aliasing by a character type is permitted. You’re right though: this may be a compiler bug. I said I wasn’t entirely sure.”

I’m not an expert or even involved in implementing compilers, but the way I interpret this is that once you’re storing values using the uchar pointer, it stops being a short and is now two uchar objects, and the aliasing violation occurs when the uchars are read back out using the lvalue of type qint16.

The exception to the aliasing restriction only seems to permit accessing stored values of any type via an lvalue of type char, but not accessing stored values of type chars via other lvalues.

tr3w says:

@The User: yes I aware of endianness and everything, I just did’nt want to post bigger example…

@anttirt, @Thiago: Thanks for mentioning memcpy. But won’t it make my code slower? Or can a good compiler eliminate the unnecessary function call and the loads and stores?

Mans says:

Type-punning through a union is actually allowed. Corrigendum 3 for C99 adds this text:

“If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called “type punning”). This might be a trap representation.”

Mindset says:

@Thiago: I see. I understand the code better now with your explanation!

bero says:

Helpful compiler flag when wondering why some project forces -fno-strict-aliasing into its Makefiles:
Change -fno-strict-aliasing to

-fstrict-aliasing -Werror=strict-aliasing

This will give you the strict-aliasing optimizations and error out when it hits questionable code. That way, you can find which files need fixing (or, if you’re lazy, which file needs to be built with -fno-strict-aliasing instead of building the entire project with that slowdown).

Mike Acton says:

Thanks for the update, Thiago. It’s always good to see new examples on this topic. There are plenty of complicated edge cases, made all the more complicated by the fact that gcc behavior changes subtly from version to version. Definitely need to know your compiler if you’re going to play with breaking “the rules”! And one of these days I should probably update that post – has it been five years already?!

Thiago Macieira says:

@Mike: whenever we talk about undefined behaviour, the following quote comes up: “people told me you cannot walk with a basketball, but I tried and I could walk just fine, so those people obviously didn’t know much about basketball”

In your example, if you’re going to try and break the rules of the compiler, it’s akin to knowing what the arbiters/umpires in the match see and don’t see.

Just want to highlight one feature of GCC that makes type-punning work: The may_alias attribute. You can use it like this:

int data = 0;
typedef float float_alias __attribute__((may_alias));
float_alias *dataf = reinterpret_cast(&data);
*dataf = 1.f;
std::cout << data << std::endl;

Now GCC will print 0x3f800000 (in decimal) reliably. That's because it knows that writes to *dataf could alias any other variable location.

I find this attribute a very useful addition to the standard. The restrict keyword goes into the other direction, i.e. even stricter aliasing requirements (just like Fortran, AFAIK. Fortran doesn't allow any aliasing and thus Fortran code often lead to the fastest programs.)
But I think every programmer will agree that sometimes there are very good (but few) reasons to make use of aliasing. With GCC you have a chance to make use of it. ICC sucks in that regard in my experience: Even unions don't work reliably. And though it calls itself __GNUC__ it doesn't understand the may_alias attribute.

Bnilsen says:

As an interesting side note to the memset optimization. Similar optimizations can be achieved when manipulating pointers of the same type if you tell the compiler the pointers do not alias each other using the keyword “restrict”. Example:
void dummy(int *restrict a, int *restrict b, int *restrict c) { *a += *c; *b += *c; }

Patrick says:

This is a wonderful article. I did something for the boost developer wiki that covers the ideas behind strict aliasing a bit slower. I’d love it if anyone would read the current version and let me know about any improvements. It’s at http://dbp-consulting.com/tutorials/StrictAliasing.html

Yonathan says:

Another good read on this topic is bit_cast from Google’s source code: http://src.chromium.org/viewvc/chrome/trunk/src/base/basictypes.h?view=markup

Commenting closed.