list_entry
読み:リスト-エントリー
外語:list_entry

 Linuxで使われている、要素が含まれる構造体などのアドレスを得るためのマクロ。container_ofと全く同じ動きをするが、用途が違うため別名となっている。
目次

書式
 マクロなので、使用するにはincludeが必要。
 #include <linux/list.h>

定義
 include/linux/list.hで定義されている。

定義1
 Linux 2.6では、次のような定義である。
#define list_entry(ptr, type, member) \
        container_of(ptr, type, member)
 つまり、container_ofの別名である。

定義2
 Androidなどでも、他のディレクトリのヘッダーファイルでは、独自の定義をしていることもある。
 最もシンプルな実装方法は次の通り。例えば次のような定義をするヘッダーファイルがあった。
#define list_entry(link, type, member) \
        ((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
 少し分かりにくいが、「&((type *)0)->member」は、アドレス0からのmemberの位置、つまりmemberの構造体内オフセットを示している。
 構造体中のにあるメンバーのポインターから、そのメンバーの構造体中の位置(オフセット)を引き算することで、その構造体の先頭アドレスを得、それに構造体のキャストをして構造体へのポインターに変えてしまうというマクロである。

概要
 list_entryは、list_headと組み合わせて使用される。
 struct list_headは、前後へのポインターのみを持つ連結リストである。for文などを使って順次アクセスすることが可能だが、このポインターから実際の構造体などを取り出すためには、ちょっとしたテクニックが必要である。このために、構造体の先頭アドレスを得るためのマクロとしてlist_entryが定義されている。
 struct list_head *から元の構造体を取り出すには、次の引数を設定する。
 こうすると、取り出したい構造体へのポインターが出て来るのである。
 計算によって構造体のアドレスを求めるため、struct list_head *は、構造体の中のどこにあってもよい。構造体の中に入っていれば、それだけでその構造体を取り出せる。

特徴

用例
 登録するリストがstruct list_head data_list;として定義されているとすると、次のように使う。
struct list_head *ptr;
struct data_struct *entry;
for (ptr = data_list.next; ptr != &data_list; ptr = ptr->next) {
    entry = list_entry(ptr, struct data_struct, node);
    printf("%d\n", entry->id);
}
 for文にすると煩雑なので、list_for_eachマクロを使うことができる。
#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)
 下は上と同義である。
struct list_head *ptr;
struct data_struct *entry;
list_for_each(ptr, &data_list) {
    entry = list_entry(ptr, struct data_struct, node);
    printf("%d\n", entry->id);
}
 このようにして、struct list_headのポインターから、list_entryを使うことで各エントリーを得ることができる。

考え方
 for文の中では、ポインター変数ptrに、struct list_headへのポインターが順次代入される。
 さて、このptrはあくまでstruct list_headへのポインターだが、次の手順で、この変数のある構造体を得ることが可能である。
  1. ptrを用意する
  2. これが格納されている構造体名を用意する
  3. 構造体の先頭から、ptr変数までのオフセットを得る
  4. ptrから、このオフセットを引けば、構造体の先頭アドレスである
  5. このアドレスを、構造体名でキャストすれば、構造体として利用できる
 オフセットを得て引き算をしてキャストをするまでの一式が、list_entryマクロとして実装されている。
 このトリッキーな計算のためには、ptr、構造体名、構造体中の変数名の三要素があれば良いことから、list_entryマクロの引数も、この三つとなっている。

再検索