2009-07-30 22 views
0

オフセット私はこの構造体を持っているとしましょう:Cの構造体は、

typedef struct nKey { 
    int num; 
    widget* widget; 
} NUMBER_KEY; 

と機能:

void dialKey(widget* widget) { 
    // Need to print 'num' of the struct that this widget resides in 
} 

は、どのように私はこれを達成するについて行くのですか?

printf("%d", * (int *) widget - sizeof(int)); // Failure.org 

編集:私のような何かをしようとした問題ではない別の方法への解決策を探して:渡されているウィジェットが実際にNUMBER_KEY構造体

編集の一員であると仮定しても安全です。

+0

構造体のメンバー間に実装定義のパディングがある可能性があるため、コードは必ずしも機能しません。 –

+0

大きなことは、ポインタがウィジェットのポインタではなく、ウィジェットへのポインタであることです。また、(int *)からsizeof(int)を減算すると、sizeof(int)intsのポインタだけが移動します。パディングの可能性はもちろんですが。 –

答えて

4

、何をする方法はありませんあなたwant(widgit *値はNUMBER_KEY構造体との関係がありません)。

void dialKey(widget** ppWidget) 
{  
    // Need to print 'num' of the struct that this widget resides in 
} 

Microsoftは(それがCで総称的リンクリストを操作するルーチンを持つことができることに役立ちます)事のこのタイプを行うための気の利いたマクロがあります:

#define CONTAINING_RECORD(address, type, field) ((type *)(\ 
           (PCHAR)(address) - \ 
           (ULONG_PTR)(&((type *)0)->field))) 
あなたが本当に好きなものを意味すると仮定すると、

あなたがそうのようにこれを使用することができます:

NUMBER_KEY* pNumberKey = CONTAINING_RECORD(*ppWidgit, NUMBER_KEY, widgit); 

printf("%d", pNumberKey->num); 
+0

既存のすべての回答が欠落していた 'widget *'と 'widget ** 'の+1。 'CONTAINING_RECORD'ははっきりとハックですが、少なくともそれは細部の詳細を隠しています... – RBerteig

+0

非常に良い点は、私は構造体宣言でポインタを見逃しました。私はそれに応じて私の答えを修正します。 –

+0

@RBertig - それはハックかもしれませんが、それは有用なものです。 –

-1

最も安全な解決策は、ウィジェット

printf("%d", widget->myKey->num); 

に関連NKEY構造体へのポインタを維持することである他のすべての方法は安全ではない

+0

「他のすべての方法は危険です」と大胆に誇張されています。 – qrdl

5

マイケルは彼の答えで説明しているように何がありますので、あなたは、与えられた制約でそれを行うことはできませんポインタグラフを「歩いて戻す」方法。物事をより明白にするために、関与(C用語ではなく、OOPの意味で)私は、オブジェクトの図を描きましょう:

+- NUMBER_KEY --+ 
| ...   | points to  
| widget field -+-----------+ 
| ...   |   | 
+---------------+   | + widget + 
          +-->| ... | 
           | ... | 
          +-->| ... | 
          | +--------+ 
        points to | 
[widget argument]-----------+ 

お知らせ矢印。それらは一方通行です - あなたはポインターから尖った値まで "歩く"ことができますが、 "歩く"ことはできません。だから、widgetオブジェクトの引数にはwidgetオブジェクトを渡すことができますが、そこには他の誰がそれを指し示すかはわかりません - NUMBER_KEY構造体のインスタンスを含みます。それについて考えてみましょう:同じwidgetにいくつかの他のポインタがあったら、それらのうちのいくつかは別のNUMBER_KEYオブジェクトですか? widgetオブジェクト内のすべてのポインタのリストを保持しないと、それをどのように追跡することができますか?実際にこれが必要な場合は、それを行う必要があります - を指してwidgetを指すようにします。

0

structのメモリレイアウトはコンパイラによって定義され、構造体メンバ間に0バイトのパディングがある場合にのみコードが機能します。通常、これはb/cの0バイトのパディングではほとんどのプロセッサの標準読み込みサイズ全体にわたって構造体のオーバーレイが行われることはお勧めしません。あなたの問題のため

いくつかの便利なマクロ:

#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) 
#define GET_FIELD_SIZE(type, field)  (sizeof(((type *)0)->field)) 

例:ちょうどwidgit *および**はdialKeyに渡されていないwidgit考える

NUMBER_KEY key; 
key.num = 55; 
int nOffSetWidget = GET_FIELD_OFFSET(NUMBER_KEY, widget); 
int *pKeyNumAddress = (int *) &(key.widget) - nOffSetWidget); 

printf("%d", * pKeyNumAddress); // Should print '55' 
+0

またはを#includeした場合、offsetof()マクロは標準です。 –

+0

私はそれがあなたの期待通りに動作するとは思わない。演算子としてsizeof(int)を使用してkey.widgetのアドレスを* intにキャストしているので、sizeof(int)* nOffSetWidgetバイト数を差し引いてnOffSetWidgetバイト数を差し引くのではなく、 標準のマクロoffsetofがあります - それを発明する必要はありません。 – qrdl

0

C規格では、あなたの場合に便利です(stddef.hヘッダで定義されている)offsetof()マクロを定義します。

#include <stddef.h> 

void DialKey(widget** foo) { 
    printf("%d", *((char *)foo - offsetof(struct nKey, widget))); 
} 

あなたは、構造体のフィールドのアドレスを渡す必要が注意、値ではなく!