95

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);

何もしていないように見えます。誰かここの穴を埋めてくれませんか?

4

7 に答える 7

96

2 つの名前空間が混在しているため、使用例container_of(dev, struct wifi_device, dev);は少し誤解を招く可能性があります。

あなたの例の最初devのものはポインターの名前を参照していますが、2番目devのものは構造体メンバーの名前を参照しています。

おそらく、この取り違えがすべての頭痛の種を引き起こしているのでしょう。実際、member引用符のパラメーターは、コンテナー構造内のそのメンバーに付けられた名前を参照しています。

このコンテナを例にとると:

struct container {
  int some_other_data;
  int this_data;
}

そして、マクロを使用してポインターを取得するメンバーint *my_ptrへのポインター:this_datastruct container *my_container

struct container *my_container;
my_container = container_of(my_ptr, struct container, this_data);

構造体の先頭へのオフセットをthis_data考慮することは、正しいポインター位置を取得するために不可欠です。

事実上、正しい位置を取得するにはthis_data、ポインターからメンバーのオフセットを差し引く必要があります。my_ptr

それはまさにマクロの最後の行が行うことです。

于 2013-04-05T11:21:15.560 に答える
22

最後の文キャスト:

(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構造体の途中を指しているポインターがあります (そして、それがフィールド[構造体のフィールド名]へのポインターであることはわかっています) が、構造体全体 ( ) を取得したいと考えていますnumberstwoしたがって、構造内のフィールドのオフセットを計算します。

offsetof(type,member)

指定されたポインタからこのオフセットを減算します。結果は、構造体の先頭へのポインターです。最後に、このポインターを構造体型にキャストして、有効な変数を取得します。

于 2013-04-05T11:18:50.633 に答える
10

これは、gcc 拡張であるステートメント式の利用です。マクロを値を返すものとして見る場合、最後の行は次のようになります。

return (struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);

複合ステートメントの説明については、リンク先のページを参照してください。例を次に示します。

int main(int argc, char**argv)
{
    int b;
    b = 5;
    b = ({int a; 
            a = b*b; 
            a;});
    printf("b %d\n", b); 
}

出力は

b 25

于 2013-04-05T11:31:08.967 に答える