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 *から元の構造体を取り出すには、次の引数を設定する。

  • 第1引数にstruct list_head *
  • 第2引数に取り出したい構造体名
  • 第3引数に取り出したい構造体の中にある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マクロの引数も、この三つとなっている。

関連する用語
Linux
list_head
container_of
連結リスト

コメントなどを投稿するフォームは、日本語対応時のみ表示されます


KisoDic通信用語の基礎知識検索システム WDIC Explorer Version 7.04a (27-May-2022)
Search System : Copyright © Mirai corporation
Dictionary : Copyright © WDIC Creators club