c strutt catturare i dati per offset
Domanda
Diciamo che ho questa struttura:
typedef struct nKey {
int num;
widget* widget;
} NUMBER_KEY;
e una funzione:
void dialKey(widget* widget) {
// Need to print 'num' of the struct that this widget resides in
}
Come posso ottenere questo risultato? Ho provato qualcosa del tipo:
printf("%d", * (int *) widget - sizeof(int)); // Failure.org
modifica: è lecito ritenere che il widget passato sia in realtà un membro di una struttura NUMBER_KEY
modifica: cerca una soluzione al problema non un altro metodo.
Soluzione
Dato che solo un widgit * e non un widgit ** vengono passati a dialKey, non c'è modo di fare quello che vuoi (un valore widgit * non ha alcuna relazione con la struttura NUMBER_KEY). Supponendo che intendi davvero qualcosa del tipo:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
Microsoft ha una macro elegante per fare questo tipo di cose (aiuta a poter avere routine che manipolano gli elenchi collegati in modo generico in C):
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
Puoi usarlo così:
NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);
printf( "%d", pNumberKey->num);
Altri suggerimenti
Come spiega Michael nella sua risposta, non puoi farlo con determinati vincoli perché non c'è modo di " tornare indietro " il grafico del puntatore. Per rendere le cose più ovvie, lasciatemi disegnare un diagramma di oggetti (in termini di C, non in senso OOP) coinvolti:
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
Nota le frecce. Sono a senso unico: puoi " camminare " da un puntatore a un valore appuntito, ma non puoi " walk " indietro. Quindi puoi deferire l'argomento widget
della tua funzione per arrivare all'oggetto widget
, ma una volta lì, non c'è modo di dire chi altro lo punti, comprese le istanze di < code> NUMBER_KEY . Pensaci: cosa succederebbe se avessi una dozzina di altri puntatori sullo stesso widget
, alcuni dei quali provenienti da diversi oggetti NUMBER_KEY
? Come è possibile rintracciarlo senza tenere un elenco di tutti i puntatori all'interno dell'oggetto widget
? Se in realtà hai bisogno di questo, è quello che dovrai fare: fai in modo che widget
indichi il suo NUMBER_KEY
.
Il layout di memoria di una struttura è definito dal tuo compilatore, il tuo codice funzionerebbe solo se hai un riempimento di 0 byte tra i membri della struttura. Di solito questo non è raccomandato b / c Il riempimento di 0 byte avrebbe il tuo overlay di struttura attraverso le dimensioni di lettura standard della maggior parte dei processori.
Alcune macro utili per il tuo problema:
#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
Esempio:
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 definisce la macro offsetof ()
(definita nell'intestazione stddef.h
), utile nel tuo caso.
#include <stddef.h>
void DialKey(widget** foo) {
printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}
Nota che devi passare un indirizzo del campo struct, non un valore!
La soluzione più sicura è mantenere il puntatore alla relativa struttura nKey nel widget
printf("%d", widget->myKey->num);
Tutti gli altri metodi non sono sicuri