*参照元 [#j0c13b2c] #backlinks *注意 [#f475c147] -より新しいバージョンがあります。 --[[linux-4.4.1/container_of()]] *説明 [#yd8af7ae] -パス: [[linux-2.6.33/include/linux/kernel.h]] -ポインタが指す構造体のメンバ、それを含む構造体へのポインタを返す。 --例えば、 struct example { int mem_a; char mem_b; }; struct example hoge; --という構造体があったとする。 int *mem_ptr = &hoge.mem_a; --上記のような、構造体のメンバへのポインタ mem_ptr しか 分からない状態から hoge へのポインタを得たいときに container_of を 使う。 struct example *ptr = container_of(mem_ptr, struct example, mem_a); --すると ptr が指す先(hoge.mem_a)を含む構造体への ポインタ(&hoge)が得られる。 **引数 [#k503964a] -ptr --構造体のメンバへのポインタを指定する。 -type --ptr に指定したポインタが指すメンバ、これを含む「構造体名」を指定する。 マクロはここで指定した型のポインタを返す。 ---上記の例で言うと変数名の hoge ではなくて、変数の型の 名前 struct example を指定する。 -member --ptr に指定したポインタが指す「メンバ名」を指定する。 ---上記の例で言うとポインタ変数 mem_ptr ではなくて、 struct example 構造体のメンバ名である mem_a を指定する。 **返り値 [#i54f1798] -type * --指定した構造体のメンバへのポインタ(ptr に指定する)が指すメンバ (メンバの名前は member に指定する)、 これを含む構造体(構造体の型は type に指定する)へのポインタを返す。 **参考 [#f34cf27c] *実装 [#r404238c] /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ -member の型のポインタ __mptr を宣言し、ptr の値を代入する。 --一見すると変なキャストであるが、 typeof( ((type *)0)->member ) は member の型を取得するための細工である。 ---type 型のポインタにキャストした null ポインタと、 参照剥がしを使って member を参照する。 ---typeof は gcc の拡張構文で、指定した変数の型を返す。 --わざわざ member の型のポインタにキャストする理由 ---ポインタを計算するだけなら (char *) へのキャストで計算可能だが、 一旦 member の型のポインタにキャストして、 コンパイル時に型チェックをしていると思われる。 ---これにより ptr に member と異なる型のポインタを渡してしまい、 異常なポインタを参照してしまうバグを防いでいる。 例: struct st_a { int a; long b; int c; } var_a; 正しい場合 int *ptr = &var_a.a; container_of(ptr, struct st_a, a); a と b を間違えた場合 long *ptr = &var_a.b; container_of(ptr, struct st_a, a); 検出可能 a と c を間違えた場合 int *ptr = &var_a.c; container_of(ptr, struct st_a, a); 検出不可能 (type *)( (char *)__mptr - offsetof(type,member) );}) -構造体の先頭へのポインタを計算する。この値がマクロの戻り値となる。 --member を指すポインタから、メンバーのオフセットを引く。 メンバーのオフセットは構造体の先頭から、メンバーまでの距離なので、 メンバーのポインタから引いてやれば、構造体の先頭を指すポインタが得られる。 return -> ---- ---- mem_a | ---- | offset mem_b ___| ---- <- __mptr mem_c ---- ---offsetof マクロは構造体のメンバー(member)が構造体(type)の先頭から どの位置にいるか(オフセット)をバイト数で返す。 ---拡張構文ではなく C の標準的なマクロで、stddef.h で定義されている。 manpage offsetof(3) などを参照のこと。 *コメント [#xe7df4f5]