Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

#include globaux ou locaux a chaque fichier source?

11 réponses
Avatar
Vincent Lefevre
Bonjour,

J'aimerais savoir s'il y a une pratique recommandée de l'utilisation
des #include dans le cadre d'un logiciel avec plusieurs fichiers .c
(cas classique) et devant tourner sur de multiples plateformes (si
bien que tester la compilation sur une machine avant un commit ne
suffit pas toujours à détecter les erreurs). La solution actuellement
choisie dans notre logiciel: mettre les #include nécessaires au début
de chaque fichier .c, suivant les fonctions et macros utilisées par
le fichier .c en question.

Le problème qui s'est posé: j'ai déplacé une fonction d'un fichier .c
à un autre, mais j'ai oublié de mettre à jour les #include (je signale
qu'indépendamment d'autres choix qui ont pu être faits, ce genre
d'erreur ne se voit pas toujours à la compilation dans la pratique).
Comme chaque fichier .c inclut un fichier d'en-tête global au projet,
je pense à la solution alternative de mettre tous les #include dans ce
fichier d'en-tête. Qu'en pensez-vous?

D'autre part, certains en-têtes standard sont inclus conditionnellement
suivant la valeur de certaines macros (définies ou non en fonction des
options du "configure"), ce qui peut cacher des erreurs qui dépendent
du choix de ces options. Une inclusion conditionnelle est tout à fait
logique dans le cas d'un en-tête non standard (puisque justement,
l'en-tête peut ne pas exister sur certaines plateformes), mais dans
le cas d'un en-tête standard, cela me semble finalement une source
d'erreur. Vaut-il mieux éviter ces inclusions conditionnelles?

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

1 réponse

1 2
Avatar
Antoine Leca
En news:f6o3rd$1sfm$, Marc Espie va escriure:
Deux contraintes a prendre en compte:
- les entetes standards ne le sont pas toujours autant qu'on le
voudrait. J'ai vu pas mal de systeme ou il faut rajouter des
incantations comme #define _XOPEN_SOURCE pour avoir certaines des
fonctions que l'on voudrait, et ou on se retrouve generalement avec
des fonctions que l'on ne voudrait pas... bonjour les collisions.


Euh, je ne suis pas sûr de bien te suivre.

Soit le programme nécessite telle version XPG, et alors ajouter
#define _XOPEN_SOURCE est la bonne méthode, de plus cela met les choses au
clair (idem avec _POSIX_SOURCE); en fait, le programmeur aurait déjà dû
l'avoir fait, une faute pour lui (lui a compilé avec _GNU_SOURCE ou
_HPUX_SOURCE ou _LESPOUICS_SOURCE, pour lui ça marche et à-dieu-vat, etc je
vous épargne le couplet)
Le fait est que SUS|X/Open ramène un tas de nouveaux noms, mais bon cela
devait aussi être le cas chez le programmeur original, donc en principe cela
doit passer (OK, je sais que si cela se présente dans un entête public de
bibliothèque c'est coton, on touche là à une limite intrinsèque de la
compilation séparée à la mode ANSI C, les namespaces C++ ont aussi des
raisons d'être...)

Soit sur ta plateforme cible un élément (disons POSIX) demande la
déclaration d'un autre élement (lui XPG), et force un #define _XOPEN_SOURCE
qui ne devrait pas avoir droit... Mais il n'y a pas vraiment de différence
avec les plateformes qui demandent l'#inclusion de <sys/time.h> ou de
<sys/types.h> pour compiler un programme purement ANSI (ces plateformes
disparaîssent aujourd'hui, mais elles pullulaient vers 1995) ou purement
POSIX (et là on a encore des exemples...)


Là où c'est malsain, c'est que le deuxième problème, beaucoup trop fréquent
à mon goût (et qui plus est le plus souvent transitoire) amène beaucoup de
développeurs à « fixer » leurs sources en rajoutant des #include <machin.h>
voire des #define _xxx_SOURCE qui ne rajoutent pas de fonctionnalités
nouvelles, donc réduisent la portabilité de leurs programmes et allongent
sensiblement le temps de compilation. Qui plus est, la liste des #include en
tête de source devient prohibitive, ce qui amène à inventer des «
solutions » comme « l'entête global qui #inclut <tout-ce-qu'il-faut> », bref
on tue la modularité et donc la réusabilité du code produit, du point de vue
du génie logiciel c'est un désastre.


- on n'utilise rarement une bibliotheque toute seule... si elle
envahit plus que le strict minimum de l'espace de noms global,
alors il est a peu pres certain que tot ou tard,
deux bibliotheques vont se marcher sur les pieds... particulierement
pour les typedef et les struct.


Oui.

La solution serait peut-etre de tout prefixer d'un mpfr_ ou
equivalent, mais c'est un peu lourd.


C'est certes lourd, mais c'est ÀMHA indispensable à moyen terme pour éviter
le problème que tu signales ci-dessus.

Et si le projet est dans ses balbutiemments, c'est une décision de gestion
qu'il faut avoir le courage de prendre, car plus on tarde, plus il y a de
code qui utilise l'API et plus la modification est difficile à réaliser.
Même si cela fait cinq lettres de plus à taper, et cinq lettres × n
occurences qui mangent l'espace sur la ligne, c'est le prix à payer.


Antoine

1 2