0

私がこの構造体を持っているとしましょう:

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 構造体のメンバーであると想定しても安全です

編集:別の方法ではなく、問題の解決策を探しています。

4

5 に答える 5

5

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

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

矢印に注意してください。それらは一方向です-ポインタからポイントされた値まで「歩く」ことはできますが、戻ることはできません。widgetしたがって、関数の引数を尊重してwidgetオブジェクトに到達することはできますが、一度そこに到達すると、構造体のインスタンスを含め、他の誰がそれを指しているのかを知る方法はありませんNUMBER_KEY。考えてみてください。同じものへのポインタが他に12個ある場合widget、それらのいくつかは異なるNUMBER_KEYオブジェクトからのものであるとしたらどうでしょうか。widgetオブジェクト内のすべてのポインタのリストを保持せずに、どうすればそれを追跡できるでしょうか。あなたが実際にこれを必要とするならば、それはあなたがしなければならないことです-widgetそれを所有していることを指摘してくださいNUMBER_KEY

于 2009-07-30T20:00:42.973 に答える
4

ただwidgit*がdialKeyに渡されるのではなく、widgit **が渡されるとすると、あなたが望むことをする方法はありません(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);
于 2009-07-30T20:08:28.213 に答える
0

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

問題に役立ついくつかのマクロ:

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

例:

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'
于 2009-07-30T20:04:39.110 に答える
0

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

#include <stddef.h>

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

値ではなく、構造体フィールドのアドレスを渡す必要があることに注意してください。

于 2009-07-31T13:36:36.833 に答える
-1

最も安全な解決策は、ウィジェット内の関連するnKey構造へのポインターを保持することです

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

他のすべての方法は安全ではありません

于 2009-07-30T19:58:07.877 に答える