12
votes

DOS et ne pas faire de compilation conditionnelle

Quand est-ce que la compilation conditionnelle est une bonne idée et quand est-ce une idée horriblement mauvaise?

Par compilation conditionnelle Je veux dire avec #Ifdef S pour compiler uniquement certains bits de code dans certaines conditions. Le #definefind S peut-être dans un fichier d'en-tête commun ou introduit via la directive -d compilateur.


4 commentaires

Cette question est trop non spécifique et à mon avis n'a pas de réponse définitive. Pouvez-vous fournir un scénario spécifique dans lequel vous envisagez d'utiliser une compilation conditionnelle?


J'ai vu certains cas où je pense que cela a été fait plutôt mal (à mon avis) et je pensais que ce serait une bonne idée de jeter ceci à la communauté. Je suis sûr que nous pouvons trouver de bonnes lignes directrices.


@ Space_C0WB0Y Je pense que cela pourrait être mériter le wiki communautaire peut-être, plutôt que nécessairement être «non spécifique». Il existe des instances spécifiques où le préprocesseur est vraiment une bonne idée et d'autres où ce n'est pas le cas.


Êtes-vous court-circuiter ou quelque chose?


8 Réponses :


-4
votes

C'est toujours une mauvaise idée. Ce qu'il fait est de créer de multiples versions de votre code source, qui doivent toutes être testées, ce qui est une douleur, de dire le moins. Malheureusement, comme beaucoup de mauvaises choses, il est parfois inévitable. Je l'utilise dans de très petites quantités lorsque vous écrivez le code qui doit être porté entre Windows et Linux, mais si je me suis retrouvé en train de le faire beaucoup, je prendrais des alternatives, telles que deux sous-arbres de développement distincts.


7 commentaires

Je pense que vous êtes trop général ici. La compilation conditionnelle n'est pas toujours une mauvaise idée, mais plusieurs des cas d'utilisation courants sont.


Je ne peux pas être d'accord. C'est comme dire "les pointeurs sont mauvais parce que tu peux être vissé". La compilation conditionnelle peut être utilisée à droite puis il ne fait pas trop mal.


"Créez plusieurs versions ..." Ce n'est pas une faute de la compilation conditionnelle, si vous besoin pour créer différentes versions du code (comme le code multi-plate-forme), alors que vous l'écrivez, vous aurez besoin de pour tester plusieurs versions.


"Deux arbres de développement distincts" Comment va-t-il mieux que la compilation conditionnelle?


@ybung C'est mieux parce que nous avons des outils (comme VCS, DIFF, etc.) pour gérer plusieurs arbres sources - nous n'avons pas de bons outils pour gérer la compilation conditionnelle.


@unquiet: Vous n'avez pas besoin de gérer la compilation conditionnelle. Avec la compilation conditionnelle, vous écrivez le "diff" dans la source elle-même. Si vous passez à plusieurs arbres de développement alors Votre maintenance devient mal à la tête et alors vous avez besoin de VCS et d'autres outils pour gérer votre code source en double.


Plusieurs arbres sources sont une mauvaise idée. Si vous trouvez un bogue dans un endroit, vous devrez modifier plusieurs fichiers pour effectuer le correctif sur toutes les plateformes. Gardez le code localisé de manière à ce qu'il puisse être maintenu à un seul point.



2
votes

Fondamentalement, vous devriez essayer de conserver la quantité de code conditionnellement compilé au minimum, car vous devriez essayer de tester tout cela et que de nombreuses conditions rendent cela plus difficile. Il réduit également la lisibilité du code; La compilation conditionnelle des fichiers entiers est plus claire, par exemple, en mettant le code spécifique à la plate-forme dans un fichier séparé pour chaque plate-forme et que tous ont toutes les mêmes API du point de vue du reste du problème. Essayez également d'éviter de l'utiliser dans des en-têtes de fonction; Encore une fois, c'est parce que c'est un endroit où il est particulièrement déroutant.

Mais cela ne veut pas dire que vous ne devriez jamais utiliser la compilation conditionnelle. Essayez simplement de le garder court et minimal. (Où je peux, j'utilise la compilation conditionnelle pour contrôler les définitions d'autres macros qui sont ensuite utilisées dans le reste du code; cela semble être plus clair pour moi au moins.)


0 commentaires

8
votes

Les bonnes idées:

  • Guards d'en-tête (vous ne pouvez pas faire beaucoup mieux pour la portabilité)
  • Mise en œuvre conditionnelle (jonglerie avec des différences de plate-forme)
  • débogage des chèques spécifiques (affirmations, etc ...)
  • par suggestion: extern "c" { et } de sorte que les mêmes en-têtes puissent être utilisés par la mise en œuvre C ++ et par les clients C de l'API

    la mauvaise idée:

    • Changer l'API entre les drapeaux compilés, car cela oblige le client à modifier ses utilisations avec les mêmes drapeaux de compilation ... URK!

6 commentaires

Je ne sais pas si le deuxième point de votre section "bonnes idées" est vraiment valable, étant donné des bibliothèques portables telles que Boost / Apr, etc. Je devrais imaginer qu'il existe très peu de cas d'angle où il y a quelque chose de plate-forme spécifique à être manipulé dans un tel bloc. Je pense que dans ce cas particulier, vous ferez mieux de s'appuyer sur les maquillages pour créer des implémentations appropriées pour la plate-forme plutôt que la compilation conditionnelle de blocs dans le même dossier ...


Une plus bonne idée: de compiler conditionnellement extern "c" { dans les fichiers d'en-tête destinés à exposer les API C à C ++. La mauvaise idée devrait être "tout le reste".


@Nim: Je suis d'accord, je suis le projet de Clang pour le moment, qui comprend le Libc ++ de Howard Hinnant, donc je suis dans un état d'esprit assez bas de bas niveau :) @jeremyP: mentionné merci, comme pour "tout le reste", bien que cela soit tentant, Je préfère éviter les généralisations balayantes.


NIM: Boost est tout simplement trop gras pour voler, mais même l'introduction de APR comme une dépendance peut souvent être déraisonnable lorsque tout ce que vous aviez vraiment besoin était un couple d'IFDEF. D'autre part, les IFDEFS sont tout simplement mauvais si vous ne finissez jamais le code dans l'un des conditionnels. Mais ce n'est pas unique à IFDEFS de Code conditionnel normal.


@ Kusma, le problème est que le "couple d'IFDEFS" ne reste pas nécessairement un couple si c'est vraiment?


@Nim: En fait, cela fait souvent si vous maintenez votre code de manière saine.



1
votes

C'est une mauvaise idée chaque fois que vous ne savez pas ce que vous faites. Cela peut être une bonne idée lorsque vous résolvez efficacement un problème de cette façon :).

La façon dont vous décrivez la compilation conditionnelle, inclure les gardes en font partie. Ce n'est pas seulement une bonne idée de l'utiliser. C'est un moyen d'éviter les erreurs de compilation.

Pour moi, la compilation conditionnelle est également un moyen de cibler plusieurs compilateurs et systèmes d'exploitation. Je suis impliqué dans une libère qui est censée être compilable sur Windows XP et plus récente, 32 ou 64 bits, à l'aide de Mingw et Visual C ++, sur Linux 32 et 64 bits à l'aide de GCC / G ++ et sur MacOS utilisant I-Ne -rez-le-savez -Quelle (je ne maintient pas cela, mais je suppose que c'est un port de GCC). Sans les conditions de préprocesseur, il serait très impossible de créer un seul fichier source compilable n'importe où.


0 commentaires

0
votes

Dans le passé si vous vouliez produire un code véritablement portable, vous devez recourir à une forme de compilation conditionnelle. Avec une prolifération de bibliothèques portables (telles que APR, Boost, etc.) Cette raison a peu de poids impho. Si vous utilisez une compilation conditionnelle, compilez simplement des blocs de code qui n'ont pas besoin de constructions particulières, vous devriez vraiment revoir votre conception - je devrais imaginer que cela deviendrait un cauchemar à maintenir.

Après avoir dit tout cela, si vous avez besoin d'utiliser la compilation conditionnelle, je me cacherais autant que possible du corps principal du code et de limiter à des cas très spécifiques qui sont très bien compris.


0 commentaires

0
votes

Les utilisations bonnes / justifiables sont basées sur l'analyse des coûts / avantages. Évidemment, les gens ici sont très conscients des risques:

  • dans la liaison d'objets qui ont vu différentes versions de classes, de fonctions, etc.
  • en faisant du code difficile à comprendre, à tester et à la raison de

    Mais, il y a des utilisations qui tombent souvent dans la catégorie nette-avantages:

    • Guards d'en-tête
    • Capitalisations de code pour les logiciels distincts «Ecosystems», tels que Linux par rapport à Windows, Visual C ++ versus GCC, optimisations spécifiques à la CPU, parfois de taille de mots et de facteurs d'endansion (cependant avec C ++, vous pouvez souvent les déterminer à la compilée via le piratage, mais Cela peut prouver Messier toujours) - Abstrait éloigne les différences de niveau inférieur pour fournir une API cohérente dans ces environnements
    • Interagir avec le code existant qui utilise le préprocesseur définit pour sélectionner des versions d'API, de normes, de comportements, de sécurité du thread, de protocoles, etc. (triste mais vrai)
    • Compilation pouvant utiliser des fonctionnalités facultatives lorsqu'il est disponible (penser à GNU Configurer les scripts et tous les tests qu'ils effectuent sur des interfaces OS, etc.)
    • Demandez que le code supplémentaire soit généré dans une unité de traduction, telle que l'ajout principal () pour une application autonome par rapport à une bibliothèque
    • Contrôle du code Inclusion pour des modes de construction logiques distincts tels que le débogage et la libération

0 commentaires

1
votes

Une autre utilisation pragmatique de compile conditionnelle consiste à "commenter" des sections de code contenant des commentaires "C" standard (I.E. / * * /). Certains compilateurs n'autorisent pas la nidification de ces commentaires, par exemple: xxx

(comme vous pouvez le constater dans la sélection de la syntaxe, Stackoverflow ne nid pas les commentaires.)

Peut utiliser #Ifdef pour obtenir le bon effet, par exemple: xxx


3 commentaires

Pourquoi ne pas utiliser le plus simple #if 0 ?


__ NOT_DEFINÉ __ est réservé à la mise en œuvre (selon les spécifications de la langue) car il contient des doubles traits de soulignement.


Bon point. Éditera l'article original pour contenir un soulignement de premier plan.



2
votes

Ne mettez pas IFDEF dans votre code.
Cela rend vraiment difficile de lire et de comprendre. Veuillez rendre le code aussi facile à lire que possible pour le responsable (il sait où vous vivez et possède une hache).

masque le code conditionnel dans des fonctions séparées et utilisez l'IFDEF pour définir les fonctions utilisées.

ne utilise la partie d'autre pour faire une définition. Si vous dingez que vous dites, une plate-forme est unique et que tous les autres sont les mêmes. Ceci est peu probable, ce qui est probablement que vous savez que vous savez ce qui se passe sur quelques plates-formes, mais vous devez utiliser la section #elle pour coller un #Error, donc lorsqu'il est porté à une nouvelle plate-forme, un développeur doit résoudre explicitement la condition de Sa plate-forme.

xh xxx

ne doit pas être tenté d'étendre une macro dans plusieurs lignes de code. Cela mène à la folie.

pH xxx

Si vous développez le code sur Windows, testez sur Solaris 3_1_1 plus tard, vous pouvez trouver des bugs inattendus lorsque les gens font des bugs comme: xxx


2 commentaires

x.h: juste pour l'exactitude: API Mentionné: Unix sait sommeil (secondes), gagnez le sommeil (MS) (je suis sûr que Loki sait, juste un bout de stylo ...)


P.H: Je veux juste annoter: être plus précis: avoir plusieurs déclarations dans la même macro (tout garder sur une seule ligne ne change rien); D'autre part: on peut faire de telles choses, si on leur fait raison (e. g. en enveloppant les déclarations dans une instruction DO {/*...*/} (FALSE)). Quoi qu'il en soit, je ne veux pas propager cela, d'autres moyens (comme l'allusion de la fonction) sont plus appropriés dans la plupart des cas.