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/