5

Does C++ guarantee that offsetof(U, m) always returns zero for any union U and its member m or are there cases when it's non-zero?

union U {
  M m;
  ...
};
timrau
  • 22,578
  • 4
  • 51
  • 64
vitaut
  • 49,672
  • 25
  • 199
  • 336

2 Answers2

6

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.

yao99
  • 870
  • 5
  • 12
  • @HTNW By [11.2.5](http://eel.is/c++draft/class.prop#5), a standard-layout union is a standard-layout class. But if it's not standard-layout, as you say, it may be non-defined. – yao99 Aug 01 '20 at 01:47
2

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 the offsetof 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.)

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35