Dans certains environnements, la compilation sera la plus rapide si l'on n'inclut que les fichiers d'en-tête dont on a besoin. Dans d'autres environnements, la compilation sera optimisée si tous les fichiers source peuvent utiliser la même collection principale d'en-têtes (certains fichiers peuvent avoir des en-têtes supplémentaires au-delà du sous-ensemble commun). Idéalement, les en-têtes doivent être construits de sorte que plusieurs opérations #include n'aient aucun effet. Il peut être bon d'entourer les instructions #include de vérifications pour l'inclusion-guard du fichier à inclure, bien que cela crée une dépendance sur le format de cette garde. De plus, en fonction du comportement de mise en cache des fichiers d'un système, une #inclusion inutile dont la cible finit par être complètement # ifdef'ed ne peut pas prendre longtemps.
Une autre chose à considérer est que si une fonction prend un pointeur vers une structure, on peut écrire le prototype comme
void foo (struct BAR_s * bar);
sans qu'une définition pour BAR_s soit dans la portée. Une approche très pratique pour éviter les inclusions inutiles.
PS - dans beaucoup de mes projets, il y aura un fichier que chaque module devrait #include, contenant des choses comme des typedefs pour des tailles entières et quelques structures et unions courantes [par exemple
typedef union {
non signé long l;
lw court non signé [2];
non signé char lb [4];
} U_QUAD;
(Oui, je sais que j'aurais des problèmes si je passais à une architecture big-endian, mais comme mon compilateur n'autorise pas les structures anonymes dans les unions, l'utilisation d'identificateurs nommés pour les octets dans l'union nécessiterait qu'ils soient accessibles comme theUnion.b.b1 etc. qui semble plutôt ennuyeux.