5

I opened stddef.h and saw this:

#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
    #ifdef __cplusplus
        #define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif

In branch of __cplusplus (In case of C++ compiler) there is very strange implementation, I think it's redundant. Else branch (case of C compiler) has simpler calculation of field offset. And I tested it, it works. For what used this strange casts and type qualifiers in first case?

Artem Selivanov
  • 1,867
  • 1
  • 27
  • 45
  • @RemyLebeau I think I disagree with your statement. C++ casts are *safer* than C cast. But: C style cast does have compile-time checks: you can't cast between unrelated classes for instance. And while C++ casts have more compile-time checks, it still lets you do invalid things: you can for instance reinterpret_cast between int and float: `int a = 24; float f = *reinterpret_cast(&a);` this compiles without any errors – bolov Nov 10 '17 at 10:14
  • @bolov That's still a cast between pointers, though. But ``reinterpret_cast`` is safer than a C-style cast because the latter will do any of that which ``static_cast``, ``reinterpret_cast`` and ``const_cast`` do, or even some combination of one of the former with the latter (e.g. ``static_cast`` plus ``const_cast``). – Arne Vogel Nov 10 '17 at 11:25
  • By the way, if user code contained a null pointer dereference, it would be undefined behavior. However, this is in a platform header, and the platform devs have special rights… – Arne Vogel Nov 10 '17 at 11:29
  • 1
    @ArneVogel yes, I've said that C++ casts is safer than C cast – bolov Nov 10 '17 at 12:47

1 Answers1

12

operator & can be overloaded for the type of m, so &((s*)0)->m) would call that operator & instead of taking m's address.

And const volatile is there in the reinterpret_cast's type so that it works even when m is const and/or volatile.

Note that in C++11, there is std::addressof(x) which always takes the address of x regardless of operator & overloads. It's likely to be implemented in a similar fashion to what you see in the question.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 4
    Note that C++11 and later have [`std::addressof()`](http://en.cppreference.com/w/cpp/memory/addressof) to handle the `operator&` issue. `offsetof()` could be written as `#define offsetof(s,m) ((size_t)std::addressof(((s*)0)->m))` – Remy Lebeau Nov 10 '17 at 10:02
  • @RemyLebeau Good point. I was thinking about it, but didn't mention it in the end. Did now. – Angew is no longer proud of SO Nov 10 '17 at 10:05