のマクロoffsetof
を<cstddef>
見ていて、可能な実装が経由であることがわかりました
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
私はそれを試してみましたが、実際には期待どおりに動作します
#include <iostream>
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
struct S
{
char x;
short y;
int z;
};
int main()
{
std::cout << my_offsetof(S, x) << '\n';
std::cout << my_offsetof(S, y) << '\n';
std::cout << my_offsetof(S, z) << '\n';
S s;
std::cout << (void*) &((&s)->x) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->y) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->z) << '\n'; // no more relative offsets
}
私が行った唯一の変更は、アドレスをポインターとして表示したいので、void*
の代わりに最終キャストを使用することです。size_t
私の質問:
- コードは完全に合法ですか。つまり、 を介してメンバーに「アクセス」し、
nullptr
そのアドレスを取得することは合法ですか? そうであれば&(((type*)nullptr)->member)
、メンバーのアドレスを 0 から相対的に計算しているように見えますが、これは本当ですか? (最後の 3 行で のアドレスに対するオフセットを取得しているようですs
)。 - マクロ定義から最後のキャストを削除すると
(void*)
、segfault が発生します。なんで?&(((type*)nullptr)->member)
type のポインターであってはなりませんかtype*
、またはここで型が何らかの形で消去されていますか?