fadedbee
fadedbee

Reputation: 44765

Does a union of a pointer and an array of pointers guarantee that the single pointer has the same address as the first element of the array?

With the struct:

struct stree {
    union {
        void *ob;
        struct stree *strees[256];
    };
};

Do the C standards (particularly C11) guarantee that ob is an alias of stree[0]?

Upvotes: 2

Views: 104

Answers (1)

Lundin
Lundin

Reputation: 214060

Maybe. The C standard only guarantees the following, 6.3.2.3:

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

In theory/formally, a void* doesn't need to have the same memory representation as a pointer to object. Whenever it encounters such a conversion, it could in theory do some tricks like keeping track of the original value, to restore it later.

In practice, void* and object pointers have the same size and format on any sane system, because that's by far the easiest way to sate the above requirement. Systems with extended addressing modes for objects exist, but they don't work as the C standard intended. Instead they use non-standard extensions by inventing near and far pointer qualifiers, which could then be applied either to void* or an object pointer. (Some examples of this are low-end microcontrollers and old MS DOS.)

Bottom line: designing for portability to insane or fictional systems is a huge waste of time. Toss in a static_assert(sizeof(void*) == sizeof(int*), "...") and that should be enough. Because in practice you're not going to find a system with magical or mysterious void* format. If you do, deal with it then.

What you have to keep in mind though, is that void* in itself is a different type, so you can't generally access the memory where the void* is stored through another pointer type (strict pointer aliasing). But there are a few exceptions to the strict aliasing rule, type punning through unions is one of them.

So regarding your union, the void* and the first object pointer are guaranteed to be allocated starting at the same address, but again their respective sizes an internal formats could in theory be different. In practice you can assume that they are the same, and because you use a union you aren't breaking strict aliasing.

As for best practice, it is to avoid void* in the first place, as there's very few places where you actually need them. For the few cases where you need to pass some generic pointer around, it is often better to use uintptr_t and store the result as an integer.

Upvotes: 1

Related Questions