linux-kernel 引数 c言語 - Linuxカーネルでのcontainer_ofマクロの理解
最後の文のキャスト:
(type *)(...)
指定されたtype
へのポインタ ポインタは、与えられたポインタからのオフセットとして計算されますdev
:
( (char *)__mptr - offsetof(type,member) )
cointainer_of
マクロを使用するときは、指定されたフィールドのポインタを含む構造体を取得する必要があります。 例えば:
struct numbers {
int one;
int two;
int three;
} n;
int *ptr = &n.two;
struct numbers *n_ptr;
n_ptr = container_of(ptr, struct numbers, two);
構造体の中央を指すポインターがあります(そして、それはtwo
のフィールド [ 構造体のフィールド名 ]へのポインターです)が、構造体全体( numbers
)を取得したいと考えています。 したがって、構造内のtwo
フィールドのオフセットを計算します。
offsetof(type,member)
このオフセットを与えられたポインタから減算する。 結果は構造体の先頭へのポインタです。 最後に、このポインタを有効な変数を持つ構造体型にキャストします。
私がLinuxカーネルをブラウズしていたとき、次のように定義されたcontainer_of
マクロが見つかりました:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
私はcontainer_ofのことを理解していますが、私が理解していないのは最後の文です。
(type *)( (char *)__mptr - offsetof(type,member) );})
我々は、次のようにマクロを使用する場合:
container_of(dev, struct wifi_device, dev);
最後の文の対応する部分は次のようになります。
(struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);
何もしないように見える。 誰でもここに空欄を記入してください。
少しリアルな文脈では、 例として赤黒のツリーを使用すると、より明確になります。これはcontainer_of
を理解する方法です。
Documentation/rbtree.txt
ように、Linuxカーネルコードでは、むしろrb_nodeにはデータエントリが含まれていません
rbtreeツリー内のデータノードは、struct rb_nodeメンバーを含む構造体です。
struct vm_area_struct
(ファイルinclude/linux/mm_types.h:284
)はそのような構造体ですが、
同じファイルに、マクロrb_entry
があります。
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
明らかに、 rb_entry
はrb_entry
と同じです。
mm/mmap.c:299
で関数定義browse_rb
中にrb_entry
使用法がありrb_entry
:
static int browse_rb(struct mm_struct *mm)
{
/* two line code not matter */
struct rb_node *nd, *pn = NULL; /*nd, first arg, i.e. ptr. */
unsigned long prev = 0, pend = 0;
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct vm_area_struct *vma;
vma = rb_entry(nd, struct vm_area_struct, vm_rb);
/* -- usage of rb_entry (equivalent to container_of) */
/* more code not matter here */
今は明らかです、 container_of(ptr, type, member)
、
-
type
はコンテナ構造体です。ここではstruct vm_area_struct
-
member
はtype
instanceのメンバの名前です。ここではvm_rb
です。タイプはrb_node
。 -
ptr
はtype
インスタンスのポインター・ポインター・member
、ここではrb_node *nd
です。
この例のように、 container_of
doは、
- 与えられた
obj.member
アドレス(ここではobj.vm_rb
)は、obj
のアドレスを返します。 - 構造体は連続したメモリのブロックなので、
obj.vm_rb
からoffset between the struct and member
差し引いたアドレスがコンテナのアドレスになります。
include/linux/kernel.h:858
- container_of
定義
include/linux/rbtree.h:51
- rb_entry
定義
mm/mmap.c:299
- rb_entry
include/linux/mm_types.h:284
- struct vm_area_struct
Documentation/rbtree.txt:
- 赤黒の樹の文書化
include/linux/rbtree.h:36
- struct rb_node
定義
PS
上記のファイルは、現在の開発版4.13.0-rc7
ます。
file:k
はfile:k
番目の行を意味しfile
。