Type punning with void * without breaking the strict aliasing rule in C99

c, c99, strict-aliasing, type-punning, void-pointers

Solution

`void *` has nothing to do with type-punning. Its main purposes are:

To allow for generic allocation and freeing operations that don't care about the type of the object the caller is storing there (e.g. `malloc` and `free`).

To allow a caller to pass a pointer to an arbitrary type through a function that will pass it back via a callback, (e.g. `qsort` and `pthread_create`). In this case, the compiler cannot enforce type checking; it's your responsibility when writing the caller and callback to ensure that the callback accesses the object with the correct type.

Pointers to `void` are also used in a few places (like `memcpy`) that actually operate on an object as the overlaid `unsigned char []` representation for the object. This could be seen as type-punning, but it's not an aliasing violation because `char` types are allowed to alias anything to access its representation. In this case, `unsigned char *` would also work, but `void *` has the advantage that pointers automatically convert to `void *`.

In your example, since the original type is `int` and not a union, there is no legal way to type-pun and access it as `short`. You could instead copy the value of `x` to a union, perform well-defined type-punning there, then copy it back. A good compiler should omit the copy entirely. Alternatively, you could break the write down into `char` writes and then it would be legal aliasing.

Problem

I recently came across the strict aliasing rule, but I'm having trouble understanding how to use `void *` to perform type punning without breaking the rule. I know this breaks the rule: ``` int x = 0xDEADBEEF; short *y = (short *)&x; *y = 42; int z = x; ``` And I know that I can safely use a union in C99 for type-punning: ``` union{ int x; short y; } data; data.x = 0xDEADBEEF; data.y = 42; int z = data.x; ``` But how do I use `void *` to safely perform type-punning in C99? Is the following correct: ``` int x = 0xDEADBEEF; void * helper = (void *)&x; short *y = (short *)helper; *y = 42; int z = x; ``` I suspect that code will still break the strict aliasing rule since the memory at variable `x`'s address can be modified by both `x` and a dereferenced `y`. If type-punning is undefined via `void *`, what is the purpose of the `void *` in C99?

Original source