c struct saisissant les données par offset
Question
Disons que j'ai cette structure:
typedef struct nKey {
int num;
widget* widget;
} NUMBER_KEY;
et une fonction:
void dialKey(widget* widget) {
// Need to print 'num' of the struct that this widget resides in
}
Comment puis-je accomplir cela? J'ai essayé quelque chose comme:
printf("%d", * (int *) widget - sizeof(int)); // Failure.org
modifier: il est prudent de supposer que le widget transmis est en fait un membre d'une structure NUMBER_KEY
modifier: rechercher une solution au problème et non une autre méthode.
La solution
Étant donné qu'un widgit * et non un widgit ** a été passé dans dialKey, il n'y a aucun moyen de faire ce que vous voulez (une valeur widgit * n'a pas de relation avec la structure NUMBER_KEY). En supposant que vous vouliez vraiment dire quelque chose comme:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
Microsoft a une bonne macro pour faire ce genre de choses (cela aide d’avoir des routines manipulant génériquement des listes liées en C):
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
Vous pouvez utiliser ceci comme suit:
NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);
printf( "%d", pNumberKey->num);
Autres conseils
Comme Michael l'explique dans sa réponse, vous ne pouvez pas le faire avec des contraintes données car il n'y a aucun moyen de "revenir en arrière". le graphique de pointeur. Pour rendre les choses plus évidentes, permettez-moi de dessiner un diagramme des objets (en termes C, pas au sens de la POO) impliqués:
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
Remarquez les flèches. Ils sont à sens unique - vous pouvez "marcher". d'un pointeur à une valeur précise, mais vous ne pouvez pas "marcher". retour. Ainsi, vous pouvez déférencer l'argument widget
de votre fonction pour accéder à l'objet widget
, mais une fois là, il est impossible de déterminer qui d'autre pointe dessus, y compris les occurrences de < code> NUMBER_KEY . Pensez-y: si vous aviez une douzaine d'autres pointeurs sur le même widget
, certains d'entre eux provenant de différents objets NUMBER_KEY
? Comment pourrait-il suivre cela sans garder une liste de tous les pointeurs dans l'objet widget
? Si vous en avez réellement besoin, c’est ce que vous devrez faire: faire en sorte que widget
pointe vers son propre NUMBER_KEY
.
La structure mémoire d'une structure est définie par votre compilateur. Votre code ne fonctionnerait que si vous avez 0 remplissage d'octets entre les membres de la structure. Cela n’est généralement pas recommandé car un remplissage sur 0 octets aurait pour effet que votre structure soit superposée aux tailles de lecture standard de la plupart des processeurs.
Quelques macros utiles à votre problème:
#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
exemple:
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'
Le standard C définit la macro offsetof ()
(définie dans l'en-tête stddef.h
), pratique dans votre cas.
#include <stddef.h>
void DialKey(widget** foo) {
printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}
Notez que vous devez transmettre une adresse de champ struct, et non une valeur!
La solution la plus sûre consiste à conserver le pointeur sur la structure nKey associée dans le widget
. printf("%d", widget->myKey->num);
Toutes les autres méthodes sont dangereuses