Does the 'offsetof' macro from <stddef.h> invoke undefined behaviour?

Viewed 3041

Example from MSVC's implementation:

#define offsetof(s,m) \
    (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
//                                                   ^^^^^^^^^^^

As can be seen, it dereferences a null pointer, which normally invokes undefined behaviour. Is this an exception to the rule or what is going on?

6 Answers

It is NOT undefined behavior in C++ if m is at offset 0 within the structure s, as well as in certain other cases. According to Issue 232 (emphasis mine):

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points, if any. If the pointer is a null pointer value (7.11 [conv.ptr]) or points one past the last element of an array object (8.7 [expr.add]), the result is an empty lvalue and does not refer to any object or function. An empty lvalue is not modifiable.

Therefore, the &((s *)0)->m is undefined behavior only if m is neither at offset 0, nor at an offset corresponding to an address which is one past the last element of an array object. Note that adding a 0 offset to null is allowed in C++ but not in C.

As others have noted, the compiler is allowed (and extremely likely) to not ever create the undefined behavior, and may be packaged with libraries that make use of the specific compiler's enhanced specifications.

Related