C strukturieren Sie Daten nach Offseting
Frage
Nehmen wir an, ich habe diese Struktur:
typedef struct nKey {
int num;
widget* widget;
} NUMBER_KEY;
und eine Funktion:
void dialKey(widget* widget) {
// Need to print 'num' of the struct that this widget resides in
}
Wie gehe ich vor, um das zu erreichen? Ich habe so etwas ausprobiert:
printf("%d", * (int *) widget - sizeof(int)); // Failure.org
Bearbeiten: Es ist sicher anzunehmen, dass das übergebene Widget tatsächlich ein Mitglied einer Number_Key -Struktur ist
Bearbeiten: Auf der Suche nach einer Lösung für das Problem, nicht eine andere Methode.
Lösung
Bei nur einem Widgit* und nicht einem Widgit **, der in Dialkey übergeben wird, gibt es keine Möglichkeit, das zu tun, was Sie wollen (ein Widgit* -Wert hat keine Beziehung zur Number_key Struct). Angenommen, Sie meinen wirklich so etwas wie:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
Microsoft verfügt über ein raffiniertes Makro für diese Art von Dingen (es hilft bei der manipulierenden Routinen, die verknüpfte Listen allgemein in C manipulieren):
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
Sie könnten dies so verwenden: SO:
NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);
printf( "%d", pNumberKey->num);
Andere Tipps
Wie Michael in seiner Antwort erklärt, können Sie es nicht mit gegebenen Einschränkungen tun, da es keine Möglichkeit gibt, das Zeigerdiagramm zurückzurufen. Lassen Sie mich ein Diagramm von Objekten zeichnen (in C, nicht im Oop -Sinne), um die Dinge offensichtlicher zu machen:
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
Beachten Sie die Pfeile. Sie sind ein Weg - Sie können von einem Zeiger auf spitzen Wert "gehen", aber Sie können nicht zurück "zurückgehen". Sie können also Achtung widget
Argument Ihrer Funktion, um zum zu gelangen widget
Objekt, aber einmal dort, gibt es keine Möglichkeit zu sagen, wer sonst noch darauf hinweist - einschließlich aller Fälle von NUMBER_KEY
Strukturen. Denken Sie darüber nach: Was wäre, wenn Sie ein Dutzend andere Hinweise auf dasselbe hätten widget
, einige von ihnen von verschiedenen NUMBER_KEY
Objekte? Wie könnte es möglicherweise das verfolgen, ohne eine Liste aller Zeiger in sich zu halten widget
Objekt? Wenn Sie dies tatsächlich brauchen, müssen Sie es tun - machen Sie - machen Sie widget
auf seinen Besitz hinweisen NUMBER_KEY
.
Das Speicherlayout einer Struktur wird von Ihrem Compiler definiert. Ihr Code würde nur dann funktionieren, wenn Sie 0 Byte -Polster zwischen Strukturmitgliedern haben. Normalerweise wird dies nicht empfohlen, dass B/C 0 -Bytepolsterung Ihre Strukturüberlagerung über die Standard -Lesegrößen der meisten Prozessoren verfügt.
Einige nützliche Makros für Ihr Problem:
#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
Beispiel:
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'
C Standard definiert offsetof()
Makro (definiert in stddef.h
Header), was in Ihrem Fall praktisch ist.
#include <stddef.h>
void DialKey(widget** foo) {
printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}
Beachten Sie, dass Sie eine bestehen müssen die Anschrift des Strukturfeldes, kein Wert!
Die sicherste Lösung besteht darin, den Zeiger auf die verwandte Nkey -Struktur in Widget zu halten
printf("%d", widget->myKey->num);
Alle anderen Methoden sind unsicher