ア | イ | ウ | エ | オ |
カ | キ | ク | ケ | コ |
サ | シ | ス | セ | ソ |
タ | チ | ツ | テ | ト |
ナ | ニ | ヌ | ネ | ノ |
ハ | ヒ | フ | ヘ | ホ |
マ | ミ | ム | メ | モ |
ヤ | ユ | ヨ | ||
ラ | リ | ル | レ | ロ |
ワ | ヰ | ヴ | ヱ | ヲ |
ン |
A | B | C | D | E |
F | G | H | I | J |
K | L | M | N | O |
P | Q | R | S | T |
U | V | W | X | Y |
Z | 数字 | 記号 |
Linuxで使われている、要素が含まれる構造体などのアドレスを得るためのマクロ。list_entryと同じ動きをするが、用途が違うため別名となっている。
マクロなので、使用するにはincludeが必要。
#include <linux/kernel.h>
container_ofは、linux/kernel.hで次のように定義されている。
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
typeof演算子はGCCの拡張機能で、既存の項目と同じ型の新しい項目を生成するものである。
offsetofは、linux/stddef.hで次のように定義されている。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
とても分かりにくいが、ptrから、構造体の先頭からmemberへのオフセットを引き算することで、構造体の先頭アドレスを得ている。
Androidなどでも、他のディレクトリのヘッダーファイルでは、独自の定義をしていることもある。
最もシンプルな実装方法は次の通り。例えば次のような定義をするヘッダーファイルがあった。
#define list_entry(link, type, member) \ ((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
typeof演算子などを使わずとも、この方法だけで充分目的を達することが可能ということだろう。
但し、Linuxのcontainer_ofの実装でわざわざtypeof演算子を使っていると言うことは、これでは求められない特殊な型が存在するのかもしれない。
list_head関係でよく使われるが、それに限らない。構造体のメンバーから構造体自体を得る場面では、汎用的に利用できる。
一般的な、struct list_head *から元の構造体を取り出す場合では、次の引数を設定する。
こうすると、取り出したい構造体へのポインターが出て来るのである。
計算によって構造体のアドレスを求めるため、struct list_head *は、構造体の中のどこにあってもよい。構造体の中に入っていれば、それだけでその構造体を取り出せる。
container_ofの使い方は、機能が全く同じである、list_entryと同様である。
struct list_head *p; struct inner_st *pin; struct outer_st *pout; list_for_each(p, &list) { pin = list_entry(p, struct inner_st, node); pout = container_of(pin, struct outer_st, sin); if (pout->outdata == 123) { /* 処理 */ } }
リスト中で関連付けられている中から、outer_st.outdata==123の要素を抽出する処理も、このように書くことができる。
例えば、AndroidのLEDデバイスドライバーの処理では、struct led_classdev *という構造体が使われるが、実際には、ハードウェアに応じた構造体の中にこの構造体を含んで用いている。
もしQUALCOMMのPM8xxx系PMICを用いている一般的なスマートフォンであるなら、struct pm8xxx_led_dataの中にstruct led_classdev *が入っている。
点灯や消灯などの要求がある時は、関数がstruct led_classdev *を引数として呼び出される。その関数内ではcontainer_ofを用いてstruct pm8xxx_led_dataを取り出すのである。
例えば、android/kernel/drivers/leds/leds-pm8xxx.cでは、次のようにして元の構造体を得ている。
static void pm8xxx_led_set(struct led_classdev *led_cdev, enum led_brightness value) { struct pm8xxx_led_data *led; led = container_of(led_cdev, struct pm8xxx_led_data, cdev); ... }
コメントなどを投稿するフォームは、日本語対応時のみ表示されます