Is offsetof of a union member always zero?
Yes, it's always zero. 6.8.2.4:
Two objects a and b are pointer-interconvertible if:
— they are the same object, or
— one is a union object and the other is a non-static data member of that object ([class.union]), or
— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, any base class subobject of that object ([class.mem]), or
— there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast. [Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note]
Since they are pointer-interconvertible and share the same address, offsetof(U, m)
should be zero.
Update:
If the union U
is not standard-layout, it's conditionally-supported. 17.2.4.1:
The macro offsetof(type, member-designator) has the same semantics as the corresponding macro in the C standard library header <stddef.h>, but accepts a restricted set of type arguments in this document. Use of the offsetof macro with a type other than a standard-layout class ([class.prop]) is conditionally-supported.183 The expression offsetof(type, member-designator) is never type-dependent and it is value-dependent if and only if type is dependent. The result of applying the offsetof macro to a static data member or a function member is undefined. No operation invoked by the offsetof macro shall throw an exception and noexcept(offsetof(type, member-designator)) shall be true.
But once it be supported, the only result make sense is zero since they share the same address.
There is only a guarantee of this if your union is standard-layout:
[class.mem/26]
: If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member if that member is not a bit-field. [..]
This is okay, because if it isn't standard-layout, you probably don't want to be using offsetof
anyway:
[support.types.layout/1]
: Use of theoffsetof
macro with a type other than a standard-layout class ([class.prop]) is conditionally-supported.
(It has undefined behaviour in C, and until C++17.)