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へのポインターだが、次の手順で、この変数のある構造体を得ることが可能である。
- ptrを用意する
- これが格納されている構造体名を用意する
- 構造体の先頭から、ptr変数までのオフセットを得る
- ptrから、このオフセットを引けば、構造体の先頭アドレスである
- このアドレスを、構造体名でキャストすれば、構造体として利用できる
オフセットを得て引き算をしてキャストをするまでの一式が、list_entryマクロとして実装されている。
このトリッキーな計算のためには、ptr、構造体名、構造体中の変数名の三要素があれば良いことから、list_entryマクロの引数も、この三つとなっている。
再検索