web-dev-qa-db-ja.com

Linuxのlist_entry

user/include/linux/list.h

この宣言:

#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) – (unsigned long)(&((type *)0)->member)))

誰かがこれが何であるか、そしてそれがどのように機能するかを説明できますか、事前に感謝します

P.S.できるだけ答えを単純化してください。Linuxのスレッドやプロセスについて知っています。現在、可能性を模索していますが、これに少しこだわっています。

27
likeIT

次のような2つの構造体について考えてみます。

_struct data {
    int something;
};

struct container {
    int something_before;
    struct data data_item;
    int something_after;
};
_

_struct data_値へのポインターがあると仮定します。

_struct data *data_ptr;
_

list_entry()マクロは、_data_ptr_を、ptrが指す_struct container_値を保持する_struct data_値へのポインターに変換するのに役立ちます。

_struct container *cont_ptr = list_entry(data_ptr, struct container, data_item);
_

マクロは、_data_item_内の_struct container_のオフセットを計算し、_data_ptr_ポインターからそのバイト数を減算することによって機能します。これは、_struct container *_にキャストされると、この特定の_struct container_を「内部」に保持する_struct data_への有効なポインターを提供します。

組み込みのoffsetof()マクロを使用して、マクロを少し簡略化することもできます。

_#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) – offsetof(type, member)))
_
29
Petri Lehtinen
10
stacker

このマクロは、そのメンバーの1つに指定された構造体のアドレスを見つけるために使用されます。

したがって、たとえば、構造体があるとします。

_typedef struct
{
    int i;
    int j;
} typestruct;
_

最初に知っておく必要があるのは、マクロの最後の部分です。

_ &((typestruct *)0)->j
_

メンバーのオフセットを与えるために使用されます。つまり、タイプにキャストされたzeroメモリからメンバーまでのサイズ(バイト単位)です。この場合、それはsizeof(int)です。これは、jが_int i_のすぐ下にあるためです。したがって、簡単にするために、この式の値を_4_と仮定します。マクロでも同じ結果が得られます

_offsetof(typestruct, j);
_

ここで、tempのアドレスを計算します。ここで、tempは_typestruct temp_です。これを行うには、ポインタのアドレスからメンバーの位置を引いたものを単純に計算します。ポインタのアドレスは次のとおりです。

_(typestruct *)((char *) &temp.j)
_

したがって、減算は次のようになります。

_&temp ==  (typestruct *)((char *) &temp.j) - offsetof(typestruct, j)
_

または、マクロが言うように:

_&temp ==  (typestruct *)((char *) &temp.j) - &((typestruct *)0)->j
_

あなたはもっと多くを学ぶことができます ここ そしてまたこれで 質問

(括弧は必要ですが、説明のために削除されました)

2
Dr Beco