EDIT:申し訳ありませんが、それは遅く、私はタイプミスをたくさん作りましたしなければなりません。
彼らは純粋な楽しみです! :)違いは、list_for_each_entry
は、リストを反復している間に何かを削除し、list_for_each_entry_safe
が(もちろん余分なCPU命令を犠牲にして)削除されないということです。
カーネルはlist.hの中でリンクされたリストの実装がありますが、二重リンクされたリスト(あなたが理解していると思います)で解決しました。あなたのリストはちょうどです:
リストの "ヘッド"と各ノードの両方に同じ構造体が使用されています。リストが空の場合、頭部のnext
とprev
のメンバーは、自分自身の頭を指しているだけです。したがって、リストを反復することは、頭部のnext
メンバーから始め、prev
(停止時)と同じアドレスでない限り、そのノードを呼び出すプロセスに過ぎません。それ以外の場合は、for
本体が呼び出され、container_of()
マクロを使用して実際の構造体へのポインタを取得し、それを使用して再生することができます。その後、for
の3番目のフィールドでは、次のnext
に移動します。
EDIT:whoops、私はお詫び申し上げます。パラメータの説明を求めました。さて、もしあなたが誰かの言葉を取るよりもむしろ私は直接それを調べるでしょう。そのためには、少なくともリンクリストライブラリのために存在するKernel API docs自身をお勧めします。私は、赤黒のツリーライブラリのためにそれらを追加するパッチセットを取得しようとしていますが、物事を得ることはかなりのプロセスになる可能性があります。ノートのも
:http://kernelnewbies.org/FAQ/LinkedLists
は、ここでは簡単な例です:
struct list_head my_actual_list;
struct my_struct {
struct list_head node;
/* some other members */
};
/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
struct my_struct *obj = list_entry(i, struct my_struct, node);
// do something with obj
}
list_entry
は答えではので、container_of
EDIT#2
OKためだけの別名でありますコメントであなたの質問に、私は私の答えを拡大するつもりです。 C++ STLコンテナ、C配列などと比べると、奇妙なことがいくつかありますが、この概念を理解するのが難しいのは分かりますが、いったんこの熟語に慣れれば、それはかなり自然に見えます。今後も、これらの構造体、関数&マクロの定義を見て、理解を深めてから質問してみることをお勧めします。
だから、最初のオフは、あなたのリスト内の各ノードは、タイプstruct list_head
のメンバーと自己はタイプstruct list_head
のあるリストが含まれています構造体です。したがって、コンテナは誰であり、このケースに含まれているかは、単にそれらがどのように使用されているかに依存するが、典型的には、これらのメンバーが与えられた名前で表される。イテレータのタイプはstruct list_head *
です。ここでは一例だと、私は彼らの同等のコードを通常の関数&マクロ呼び出しを置き換えます:
struct my_container {
struct list_head list;
int some_member;
/* etc. */
};
struct my_obj {
struct list_head node;
int some_member;
/* etc. */
};
void func() {
struct my_container container;
struct my_obj obj1, obj2;
struct list_head *i;
/* INIT_LIST_HEAD(&container.list); */
container.list.next = &container.list;
container.list.prev = &container.list;
/* list_add_tail(&obj1.node); */
container.list.prev = &obj1.node;
obj1.node.next = &container.list;
obj1.node.prev = &container.list;
container.list.next = &obj1.node;
/* list_add_tail(&obj2.node); */
container.list.prev = &obj2.node;
obj2.node.next = &container.list;
obj2.node.prev = &obj1.node;
obj1.node.next = &obj2.node;
/* list_for_each(i, &container.list) { */
for (i = container.list.next; i != &container.list; i = i->next) {
struct my_obj *obj = list_entry(i, struct my_obj, node);
/* do stuff */
}
}
Now go read! :)
私はあなたがLinuxカーネルを理解する本を読むことをお勧め。 – stdcall
あなたの提案をお寄せいただきありがとうございます。 – goodies