2009-07-30 30 views
0

Disons que j'ai cette struct:c struct saisir des données par offset

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 aller accomplir cela? J'ai essayé quelque chose comme:

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

edit: il est sûr de supposer que le widget étant passé est en fait un membre d'une struct NUMBER_KEY

d'édition: la recherche d'une solution au problème pas une autre méthode.

+0

Votre code ne fonctionnera pas nécessairement tel quel car il peut y avoir un remplissage défini par l'implémentation entre les membres d'une structure. –

+0

La grande chose est que le pointeur est le widget, pas le pointeur du widget. En outre, en soustrayant sizeof (int) d'un (int *) déplace ce pointeur sizeof (int) ints, pas seulement un. Sans parler de la possibilité de rembourrage. –

Répondre

4

Étant donné juste un Widgit * et non un Widgit ** être passé dans dialKey, il n'y a aucun moyen de faire ce que vous want (une valeur widgit * n'a aucun lien avec la structure NUMBER_KEY).En supposant que vous voulez vraiment dire quelque chose comme:

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

Microsoft a une macro nifty pour faire ce genre de chose (il aide à être en mesure d'avoir des routines qui manipulent des listes liées genericly en C):

#define CONTAINING_RECORD(address, type, field) ((type *)(\ 
           (PCHAR)(address) - \ 
           (ULONG_PTR)(&((type *)0)->field))) 

Vous pouvez utiliser cela comme si:

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

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

+1 pour «widget *» vs «widget **» dont toutes les réponses existantes ont manqué. 'CONTAINING_RECORD' est clairement un hack, mais au moins il cache les détails sanglants ... – RBerteig

+0

Très bon point, j'ai raté le pointeur dans la structure de la déclaration. Je vais corriger ma réponse en conséquence. –

+0

@RBertig - ce peut être un hack, mais c'est un sacrément utile. –

-1

La solution la plus sûre est de garder le pointeur à la structure nKey associée dans un widget

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

Toutes les autres méthodes ne sont pas sûrs

+0

C'est une surenchère audacieuse de dire "Toutes les autres méthodes sont dangereuses". – qrdl

5

Comme Michael explique dans sa réponse, vous ne pouvez pas le faire avec des contraintes données, car il n'y a pas façon de "revenir" le graphique du pointeur. Pour rendre les choses plus évidentes, permettez-moi de dessiner un diagramme d'objets (en C, pas dans le 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 pointue, mais vous ne pouvez pas "marcher" en arrière. Donc, vous pouvez déférer widget argument de votre fonction pour accéder à l'objet widget, mais une fois là, il n'y a aucun moyen de dire qui d'autre pointe dessus - y compris les instances de structures NUMBER_KEY. Pensez-y: et si vous aviez une douzaine d'autres pointeurs vers le même widget, certains d'entre eux à partir de différents objets NUMBER_KEY? Comment pourrait-il suivre cela sans garder une liste de tous les pointeurs dans widget objet? Si vous en avez réellement besoin, c'est ce que vous devrez faire - faites widget point à son propre NUMBER_KEY.

0

La disposition de la mémoire d'une structure est définie par votre compilateur, votre code ne fonctionnera que si vous avez un remplissage de 0 octet entre les membres de la structure. Habituellement, ce n'est pas recommandé. B/c padding 0 octets aurait votre superposition de struct à travers les tailles de lecture standard de la plupart des processeurs.

Certaines macros utiles pour 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' 
+0

Si vous #incluez ou , la macro offsetof() est standard. –

+0

Je ne pense pas que cela fonctionnera comme vous le souhaitez. Vous lancez l'adresse de key.widget à * int ainsi pointeur math avec use sizeof (int) comme unité arithmétique, donc au lieu de déduire nOffSetWidget nombre d'octets, vous déduire sizeof (int) * nOffSetWidget nombre d'octets. Et il y a macro offsetof standard - pas besoin de l'inventer. – qrdl

0

C standard définit offsetof() macro (définie dans stddef.h en-tête), ce qui est à portée de main dans votre cas.

#include <stddef.h> 

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

Notez que vous devez passer une adresse de champ struct, pas une valeur!