5

linux-2.6.16/include/linux/stddef.h のコードは次のとおりです。

 #undef offsetof
 #ifdef __compiler_offsetof
 #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif

#define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname))

「((size_t) &((TYPE *)0)->MEMBER)」を理解するには?
ありがとうございました

4

3 に答える 3

13

一連の操作は次のように説明できます。

    1.                         0
    2.                ((TYPE *)0)
    3.              ( ((TYPE *)0)->MEMBER )
    4.             &( ((TYPE *)0)->MEMBER )
    5.  ( (size_t) &( ((TYPE *)0)->MEMBER )
  1. すべてが number で始まります0
  2. 0へのポインタにキャストされますstruct TYPE。IOW、プログラムのデータセグメントの先頭にそのようながあるとコンパイラに信じ込ませていstructます(これは一般的に危険ですが、この特定のケースではそうでない理由については後で説明します)。
  3. 次に、MEMBERこの中のメンバーstructが参照されます。
  4. その内容は使用されませんが、そのアドレスは取得されます (with &),
  5. そして、この住所は数値型に変換されますsize_t

構造体の「開始」の0アドレスが として指定されているため、(数値に変換された場合の) のアドレスはMEMBER、構造体内のオフセットです。

この特定のコードが無害である理由は、メモリ位置が書き込まれず、アクセスさえされないためです。すべてには、それらの位置へのポインター (ただし、その内容ではない) と数値が含まれます。それらはすべて、マシンレジスタまたは通常のローカルスタックに保持されていました。

次の式:

      ( (size_t) &( ((TYPE *)3264)->MEMBER ) - 3264 )

も機能します。3264 は、任意の番号を表します。読みやすくするために括弧セットを追加しました。

于 2013-09-01T02:51:17.307 に答える
3

これは、コンパイラによるサポートがない場合の機能をエミュレートできるようにするハックです。ベースアドレスがゼロに設定されている場合、のアドレスがそのオフセットと等しいoffsetofという事実を利用します。MEMBER

次の例を検討してください。

struct Test {
    char text[32];
    int count;
}

struct Testがアドレスに割り当てられている場合0xC000、 のアドレスはtextになり0xC000、 のアドレスは にcountなります0xC020。ただし、ベース アドレスが 0 の場合 (標準では許可されていません)、 のアドレスはtext0 になり、カウントのアドレスは になります0x20。これらのアドレスをキャストsize_tすると、対応するメンバーのオフセットが得られます。

于 2013-09-01T02:50:17.163 に答える
0

It returns the offset of the specified structure member by baseing it off of address 0. 最初にアドレス 0 を正しい型 ((TYPE*)キャスト) にキャストし、次に指定されたメンバーのオフセットをそのベース アドレスに追加します。ベース アドレスが 0 であるため、マクロで指定したメンバーのオフセットを効率的に取得できます。

于 2013-09-01T02:49:34.787 に答える