0

私の先生は、Cでリンクされたキューを実装する際に次のプリプロセッサマクロを使用するように指示しています。アイデアは、キューにデータを保持させないことでキューを汎用化し、キュー内のノードとそれに属するデータを保持するラッパー構造体を他の場所に配置することです。

以下のマクロは、キューからノード(つまり、ノード)、ラッパー構造体のタイプ(つまり、struct Wrapper)、およびラッパーのキューノード要素の名前(つまり、qnode(Wrapperにはqnodeという要素があります))を取り込みます。

次に、マクロは、渡されたノードが含まれている構造体ラッパーを返します。

したがって、呼び出しは次のようになります。

queue_entry(node, struct Wrapper, qnode)

これは私の目には非常にクールで、うまく機能します(私の先生がどのように書いたかを見ると、もっと良いでしょう!)。しかし、私は誰かがそれが実際にどのように機能するかを私に説明できることを望んでいましたか?舞台裏で実際に何が起こっているのか途方に暮れているからです。

マクロ:

#define queue_entry(NODE, STRUCT, MEMBER)               \
    ((STRUCT *)((uint8_t*)(NODE) - offsetof(STRUCT, MEMBER)))
4

2 に答える 2

1

マクロをCのsedと考えてください

QUEUE_ENTRY(a、b、c)が表示される場所では、次のようになります。

((b *)((uint8_t *)(a)-offsetof(b、c)))

これらの置換はすべて、コンパイルされる前に行われます。

于 2012-12-02T03:08:42.563 に答える
1

C構造体のメンバー要素には、アドレスの固定された違いがあります。この違いは、コンパイル時に定義されます。

を使用して、このアドレスの違いを取得できます&(struct_object.member) - &struct_object。これはによって返されるものですoffsetof

たとえば、以下の構造体を検討してください。

struct abcd{
int a; // 4 bytes
int b; // another 4 bytes
char c;// 1 byte
}

次にoffsetof(struct abcd,c)、8を返しますoffsetof(struct abcd,a)。0などになります。構造体内の「パディング」または「配置」も、オフセットを決定する際に役割を果たします。ただし、これは実行時ではなく、コンパイル時に決定されます。

したがって、メンバーのアドレス(この例ではchar c)があり、構造がない場合は、メンバーアドレスからメンバーアドレスオフセットを引くことにより、親構造のアドレスを取得できます。

あなたの例では、メンバーのアドレスはノードに含まれています。したがって、メンバーofsetを減算すると、コンテナ構造体のアドレスが取得されます。

Linuxカーネルのソースコードでは、同じマクロが名前で利用できますcontainer_of(大文字とアンダースコアがある場合は忘れました)。

于 2012-12-02T03:20:22.587 に答える