31 votes

Pourquoi éviter #ifdef dans les fichiers .c?

Un programmeur que je respecte a dit que dans le code C, #if et #ifdef devraient être évités à tout prix, sauf éventuellement dans les fichiers d'en-tête. Pourquoi serait-il considéré comme une mauvaise pratique de programmation d'utiliser #ifdef dans un fichier .c?

55voto

Alex Budovski Points 8932

Dur à maintenir. Mieux utiliser les interfaces abstraites de plate-forme spécifique code d'abuser de compilation conditionnelle par la dispersion #ifdefs tous les dessus de votre mise en œuvre.

E. g.

void foo() {
#ifdef WIN32
   // do Windows stuff
#else
   // do Posix stuff
#endif
   // do general stuff
}

N'est pas agréable. Au lieu de fichiers foo_w32.c et foo_psx.c avec

foo_w32.c:

void foo() {
    // windows implementation
}

foo_psx.c:

void foo() {
    // posix implementation
}

foo.h:

void foo();  // common interface

Alors 2 makefiles1: Makefile.win, Makefile.psx, avec chaque compilation du appropriés .c fichier et en le liant à l'encontre de la droite de l'objet.

Modification mineure:

Si foo()'s la mise en œuvre dépend d'un code qui s'affiche sur toutes les plateformes, E. g. common_stuff()2, appelez simplement que dans votre foo() des implémentations.

E. g.

commun.h:

void common_stuff();  // May be implemented in common.c, or maybe has multiple
                      // implementations in common_{A, B, ...} for platforms
                      // { A, B, ... }. Irrelevant.

foo_{w32, psx}.c:

void foo()  {  // Win32/Posix implementation
   // Stuff
   ...
   if (bar) {
     common_stuff();
   }
}

Alors que vous pourriez être la répétition d'un appel de fonction à l' common_stuff(), vous ne pouvez pas paramétrer votre définition de l' foo() par la plate-forme, sauf s'il suit un modèle très particulier. Généralement, les différences de plate-forme nécessite complètement différentes implémentations et ne suivez pas ces modèles.


  1. Les Makefiles sont utilisés ici illustratively. Votre système de construction peut pas utiliser make à tous, comme si vous utilisez Visual Studio, CMake, Scons, etc.
  2. Même si common_stuff() a plusieurs implémentations, variant par la plate-forme.

6voto

paul Points 862

(Un peu hors de la question posée)

J'ai vu une astuce une fois, ce qui suggère l'utilisation de l' #if(n)def/#endif blocs pour une utilisation dans le débogage/isoler le code, au lieu de commenter.

Il a été suggéré pour aider à éviter des situations dans lesquelles la section commentaire déjà eu des commentaires de documentation et d'une solution comme les suivants devraient être mis en œuvre:

/* <-- begin debug cmnt   if (condition) /* comment */
/* <-- restart debug cmnt {
                              ....
                          }
*/ <-- end debug cmnt

Au lieu de cela, ce serait:

#ifdef IS_DEBUGGED_SECTION_X

                if (condition) /* comment */
                {
                    ....
                }
#endif

Semblait être une bonne idée pour moi. Souhaite que je pourrais rappeler la source afin que je puisse le lien :(

3voto

Simeon Pilgrim Points 4263
  1. Parce que lorsque vous effectuez des résultats de recherche, vous ne savez pas si le code est entré ou sorti sans le lire.

  2. Parce qu'ils doivent être utilisés pour les dépendances OS / Platform, et donc ce type de code doit être dans des fichiers comme io_win.c ou io_macos.c

3voto

catchmeifyoutry Points 4956

Mon interprétation de cette règle: la logique de votre programme (algorithmique) ne doit pas être influencée par les définitions du préprocesseur. Le fonctionnement de votre code doit toujours être concis. Toute autre forme de logique (plate-forme, débogage) doit pouvoir être résumée dans les fichiers d'en-tête.

Il s'agit plus d'une ligne directrice que d'une règle stricte, à mon humble avis. Mais je suis d'accord que les solutions basées sur la syntaxe c sont préférées à la magie du préprocesseur.

2voto

DigitalRoss Points 80400

Un objectif raisonnable, mais pas si grand comme une règle stricte

Les conseils d'essayer et de garder préprocesseur des instructions conditionnelles dans les fichiers d'en-tête est bonne, car elle vous permet de sélectionner des interfaces conditionnellement mais pas la litière avec le code source de confusion et laid préprocesseur logique.

Cependant, il y a des tas et des tas de code qui ressemble à l'exemple ci-dessous, et je ne pense pas qu'il y est une meilleure alternative. Je pense que vous avez cité une indication raisonnable, mais pas un grand or-tablette-commandement.

#if defined(SOME_IOCTL)
   case SOME_IOCTL:
   ...
#endif
#if defined(SOME_OTHER_IOCTL)
   case SOME_OTHER_IOCTL:
   ...
#endif
#if defined(YET_ANOTHER_IOCTL)
   case YET_ANOTHER_IOCTL:
   ...
#endif

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X