c – offsetof()のこの実装はなぜ機能するのですか?

ANSI Cでは、offsetofは次のように定義されています。

#define offsetof(st, m) \
    ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

NULLポインタを間接参照しているので、なぜこれがセグメンテーション違反を引き起こさないのでしょうか。それとも、オフセットのアドレスだけが取り出されるのを見て、実際にそれを間接参照せずに静的にアドレスを計算するという、ある種のコンパイラハックですか。このコードも移植可能ですか?

ベストアンサー
上記のコードのどの部分でも、間接参照されているものは何もありません。逆参照は、*または – >の場合に発生します。参照された値を見つけるためにアドレス値に使用されます。上記の*の唯一の使用は、キャストを目的とした型宣言にあります。

– >演算子は上記で使用されていますが、値にアクセスするためには使用されていません。代わりに、値のアドレスを取得するために使用されていました。これは、もう少し明確にするための非マクロコードのサンプルです。

SomeType *pSomeType = GetTheValue();
int* pMember = &(pSomeType->SomeIntMember);

2行目では、実際には参照は行われません(実装依存)。 pSomeType値内のSomeIntMemberのアドレスを返すだけです。

あなたが見ているのは、任意の型とcharポインタの間の多くのキャストです。 charの理由は、それがC89標準の唯一の(おそらく唯一の)型の1つであり、明示的なサイズを持つためです。サイズは1です。サイズが1であることを確認することで、上記のコードは値の真のオフセットを計算するという悪魔のような魔法をかけることができます。

転載記事の出典を記入してください: c – offsetof()のこの実装はなぜ機能するのですか? - コードログ