En C, un pointeur sur une structure pointe-t-il toujours sur son premier membre?

Supposons que j’ai un certain nombre de structures C pour lesquelles je voudrais qu’un ensemble particulier de fonctions fonctionne.

Je me demande si l’approche suivante est une approche légitime:

typedef struct Base { int exampleMember; // ... } Base; typedef struct Foo { Base base; // ... } Foo; typedef struct Bar { Base base; // ... } Bar; void MethodOperatesOnBase(void *); void MethodOperatesOnBase(void * obj) { Base * base = obj; base->exampleMember++; } 

Dans l’exemple, vous remarquerez que les deux structures Foo et Bar commencent par un membre Base .

Et, cela dans MethodOperatesOnBase , j’ai MethodOperatesOnBase le paramètre void * à Base * .

Je voudrais passer des pointeurs à Bar et des pointeurs à Foo à cette méthode et m’appuyer sur le premier membre de la structure pour être une structure de Base .

Est-ce acceptable ou faut-il être au courant de certains problèmes (éventuellement liés à un compilateur)? (Telle une sorte de système d’emballage / de remplissage qui changerait l’emplacement du premier membre d’une structure?)

Oui, la norme C garantit spécifiquement que cela fonctionnera.

(C1x §6.7.2.1.13: “Un pointeur sur un object de structure, converti de manière appropriée, pointe vers son membre initial … et inversement. Il peut y avoir un remplissage non nommé à l’intérieur de l’object de structure, mais pas à son début.”)

Je ne suis en désaccord avec aucune des réponses disant que ce que vous avez suggéré marchera, mais dans l’intérêt d’une discussion plus complète (sans vous suggérer d’utiliser C ++!), Pourquoi ne pas faire quelque chose comme:

 typedef struct Base ... /* The types defined exactly as before */ typedef struct Foo ... typedef struct Bar ... /* The function takes a Base* since that is what it actually works with*/ void MethodOperatesOnBase(Base* pbase) { /* Do something... */ } /* Now call it like this: */ Foo foo; Bar bar; MethodOperatesOnBase(&foo.base); MethodOperatesOnBase(&bar.base); 

Y a-t-il une raison qui ne fonctionne pas et vous devez utiliser void * ? Je ne vois pas que c’est beaucoup plus de travail et cela présente l’avantage de la sécurité de type.

L’ensemble de GTK + est mis en œuvre comme ça. Je ne peux pas penser à un meilleur exemple. Jetez un coup d’œil à http://git.gnome.org/browse/gtk+/tree/gtk/