这两个 offsetof 宏有什么区别?

What is the difference between these two offsetof macros?

我看到了offsetof这两个宏:

#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

有什么区别:

((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))

和:

((size_t)&(((s*)0)->m))

reinterpret_cast<type>(expression) 是一个 expression,它告诉编译器将表达式 (((s*)0)->m) 中给出的一系列位视为类型 <char const volatile&> 而不是原始类型。它们仍然对相同的数据进行操作,只是编译器将数据视为顶部表达式中的不同数据类型。

operator& 可以在 C++ 中重载。如果 operator&(const M&) 有用户定义的重载,其中 Mdecltype((s*)0)->m)(即成员的类型)并且如果重载不是 return 对象的地址,那么没有重新解释转换的宏将无法正常运行。

char 引用可能是专门使用的,因为 charunsigned charspecial guarantees 允许为任何类型起别名,并且因为不能为原始类型重载运算符。 const volatile 可能存在限定符,这样编译器就不会在成员碰巧拥有这些限定符时发出有关丢弃这些限定符的警告。

正如 T.C 在评论中指出的那样,额外的转换可能是为了防止用户定义的重载。 C 没有重载,所以不需要保护转换。