J'ai vu à la fois les définitions complètes de struct
s dans les en-têtes et uniquement les déclarations: y a-t-il un avantage à une méthode par rapport à l'autre?
Si cela fait une différence, je tape habituellement une structure comme dans le .h
typedef struct s s_t;
Pour être clair, les options sont déclaration dans le fichier d'en-tête et définition dans la classe, ou déclaration et définition dans le fichier d'en-tête. Les deux devraient donner la même convivialité, même si l’un est par couplage, non?
Je vois beaucoup de doublons, par exemple ici mais pas de correspondance exacte. S'il vous plaît corrigez-moi si je me trompe à cet égard.
Les structures privées de ce fichier doivent figurer dans le fichier .c, avec une déclaration dans le fichier .h si elles sont utilisées par une fonction quelconque du fichier .h.
Les structures publiques doivent aller dans le fichier .h.
Les deux devraient donner la même convivialité, même s’il s’agit d’un lien, ne devrait-il pas?
Non, pas lorsque vous considérez d'autres fichiers .c incluant le même en-tête. Si la définition de la structure n'est pas visible par le compilateur, les détails de cette définition ne peuvent pas être utilisés. Une déclaration sans définition (par exemple, simplement struct s;
) provoque l’échec du compilateur si quelque chose essaie de regarder à l’intérieur de struct s
, tout en lui permettant par exemple de compiler struct s *foo;
(tant que foo
n'est pas déréférencé ultérieurement).
Comparez ces versions de api.h
et api.c
:
Definition in header: Definition in implementation:
+---------------------------------+ +---------------------------------+
| struct s { | | struct s; |
| int internal; | | |
| int other_stuff; | | extern void |
| }; | | api_func(struct s *foo, int x); |
| | +---------------------------------+
| extern void | +---------------------------------+
| api_func(struct s *foo, int x); | | #include "api.h" |
+---------------------------------+ | |
+---------------------------------+ | struct s { |
| #include "api.h" | | int internal; |
| | | int other_stuff; |
| void | | }; |
| api_func(struct s *foo, int x) | | |
| { | | void |
| foo->internal = x; | | api_func(struct s *foo, int x) |
| } | | { |
+---------------------------------+ | foo->internal = x; |
| } |
+---------------------------------+
Ce client de l'API fonctionne avec l'une des versions suivantes:
#include "api.h"
void good(struct s *foo)
{
api_func(foo, 123);
}
Celui-ci passe en revue les détails de la mise en œuvre:
#include "api.h"
void bad(struct s *foo)
{
foo->internal = 123;
}
qui fonctionnera avec la version "définition dans l'en-tête", mais pas avec la version "définition dans l'implémentation", car dans ce dernier cas, le compilateur n'a aucune visibilité sur la structure de la structure:
$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$
Ainsi, la version "définition en implémentation" protège contre l'utilisation abusive ou délibérée des détails d'implémentation privés.
Si la structure doit être utilisée par d'autres unités de compilation (fichiers .c), placez-la dans le fichier d'en-tête afin de pouvoir l'inclure à tout moment.
Si la structure n'est utilisée que dans une seule unité de compilation (fichier .c), vous la placez dans ce fichier .c.
Le fait est que le placer dans un fichier d'en-tête vous permet d'utiliser la structure (ou toute autre définition) à partir de plusieurs fichiers source, en incluant simplement ce fichier d'en-tête.
Mais si vous êtes sûr qu'il ne sera utilisé que dans un seul fichier source, cela ne fera aucune différence.
Je les ai mis dans le fichier C pour le rendre plus orienté objet, voir cet article .