Indentation #defines

99

Je sais que les #defines, etc. ne sont normalement jamais indentés. Pourquoi?

Je travaille actuellement avec du code qui contient un horrible mélange de #defines, #ifdefs, #elses, #endifs, etc. Tout cela est souvent mélangé avec du code C normal. La non-indentation des #defines les rend difficiles à lire. Et le mélange de code indenté avec des #defines non indentés est un cauchemar.

Quel est l'avantage de ne pas indenter #defines? Est-ce que cela fait de moi une mauvaise personne si je les indente? N'est-ce pas beaucoup plus agréable?

#ifdef SDCC
    #if DEBUGGING == 1
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x3DC0
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x7DC0
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #else
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x4000
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x8000
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #endif
#else
    #if DEBUGGING == 1
        #define FLASH_MEMORY_END 0x7DC0
    #else
        #define FLASH_MEMORY_END 0x8000
    #endif
#endif
Rocketmagnet
la source

Réponses:

103

Le préprocesseur pré-ANSI C ne permettait pas d'espace entre le début d'une ligne et le caractère «#»; le premier "#" devait toujours être placé dans la première colonne.

Les compilateurs pré-ANSI C sont inexistants de nos jours. Utilisez le style que vous préférez (espace avant "#" ou espace entre "#" et l'identifiant).

http://www.delorie.com/gnu/docs/gcc/cpp_48.html


la source
26

Comme certains l'ont déjà dit, certains compilateurs pré-ANSI exigeaient que # soit le premier caractère sur la ligne, mais ils ne nécessitaient pas d'attacher une directive de préprocesseur, donc l'indentation a été faite de cette façon.

#ifdef SDCC
#  if DEBUGGING == 1
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x3DC0
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x7DC0
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  else
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x4000
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x8000
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  endif
#else
#  if DEBUGGING == 1
#    define FLASH_MEMORY_END 0x7DC0
#  else
#    define FLASH_MEMORY_END 0x8000
#  endif
#endif

J'ai souvent vu ce style dans les anciens en-têtes Unix mais je le déteste car la coloration de la syntaxe échoue souvent sur un tel code. J'utilise une couleur très visible pour la directive pré-processeur afin qu'ils se démarquent (ils sont à un méta-niveau et ne devraient donc pas faire partie du flux normal de code). Vous pouvez même voir que SO ne colore pas la séquence de manière utile.

Patrick Schlüter
la source
16

En ce qui concerne l'analyse des directives du préprocesseur, la norme C99 (et la norme C89 avant elle) étaient claires sur la séquence d'opérations effectuées logiquement par le compilateur. En particulier, je pense que cela signifie que ce code:

/* */ # /* */ include /* */ <stdio.h> /* */

est équivalent à:

#include <stdio.h>

Pour le meilleur ou pour le pire, GCC 3.4.4 avec '-std = c89 -pedantic' accepte en tout cas la ligne chargée de commentaires. Je ne préconise pas cela comme un style - pas une seconde (c'est horrible). Je pense juste que c'est possible.

ISO / CEI 9899: 1999 section 5.1.1.2 Phases de traduction dit:

  1. [Mappage de caractères, y compris les trigraphes]

  2. [Épissure de ligne - suppression de la nouvelle ligne de barre oblique inverse]

  3. Le fichier source est décomposé en jetons de prétraitement et séquences de caractères d'espacement (y compris les commentaires). Un fichier source ne doit pas se terminer par un jeton de prétraitement partiel ou par un commentaire partiel. Chaque commentaire est remplacé par un caractère espace. Les caractères de nouvelle ligne sont conservés. La question de savoir si chaque séquence non vide de caractères d'espace blanc autre que la nouvelle ligne est conservée ou remplacée par un caractère d'espace est définie par l'implémentation.

  4. Les directives de prétraitement sont exécutées, les appels de macro sont développés, [...]

La section 6.10 Directives de prétraitement dit:

Une directive de prétraitement consiste en une séquence de jetons de prétraitement qui commence par un # jeton de prétraitement qui (au début de la phase de traduction 4) est soit le premier caractère du fichier source (éventuellement après un espace blanc ne contenant aucun caractère de nouvelle ligne) ou qui suit un espace blanc contenant au moins un caractère de nouvelle ligne et se termine par le caractère de nouvelle ligne suivant.

Le seul différend possible est l'expression entre parenthèses `` (au début de la phase de traduction 4) '', ce qui pourrait signifier que les commentaires avant le hachage doivent être absents car ils ne sont autrement remplacés par des espaces qu'à la fin de la phase 4.

Comme d'autres l'ont noté, les préprocesseurs C pré-standard ne se comportaient pas uniformément de plusieurs manières, et les espaces avant et dans les directives de préprocesseur étaient l'un des domaines dans lesquels différents compilateurs faisaient des choses différentes, y compris ne pas reconnaître les directives de préprocesseur avec des espaces devant eux. .

Il est à noter que la suppression de la barre oblique inverse-nouvelle ligne se produit avant l'analyse des commentaires. Par conséquent, vous ne devez pas terminer les //commentaires par une barre oblique inverse.

Jonathan Leffler
la source
7

Je ne sais pas pourquoi ce n'est pas plus courant. Il y a certainement des moments où j'aime indenter des directives de préprocesseur.

Une chose qui ne cesse de me gêner (et qui me convainc parfois d'arrêter d'essayer) est que la plupart des éditeurs / IDE jetteront la directive à la colonne 1 à la moindre provocation. Ce qui est énervant comme l'enfer.

Michael Burr
la source
5

Ces jours-ci, je pense que c'est principalement un choix de style. Je pense qu'à un moment donné dans un passé lointain, tous les compilateurs n'ont pas soutenu la notion d'indentation des définitions de préprocesseur. J'ai fait quelques recherches et je n'ai pas pu étayer cette affirmation. Mais dans tous les cas, il semble que tous les compilateurs modernes soutiennent l'idée d'indenter une macro pré-processeur. Je n'ai pas de copie du standard C ou C ++ donc je ne sais pas si c'est un comportement standard ou non.

Quant à savoir si c'est du bon style ou non. Personnellement, j'aime l'idée de les garder tous à gauche. Cela vous donne un endroit cohérent pour les rechercher. Ouais, ça peut devenir ennuyeux quand il y a des macros très imbriquées. Mais si vous les indentez, vous finirez par vous retrouver avec un code encore plus étrange.

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif
JaredPar
la source
14
La raison pour laquelle ce code semble étrange est que vous avez créé deux "flux" d'indentation. Je mettrais en retrait la ligne 4 d'un niveau de plus, et je mettrais en retrait les lignes 6 et 7 de deux niveaux supplémentaires.
Kevin Laity
3
Entièrement d'accord. Je mets parfois même des accolades pour que les # if ressemblent à ceux des if.
baash05
3
J'essaie très fort d'organiser mon code de manière à ce qu'il n'ait pas de #ifdef lignes dans les parties où j'ai du code réel. Au lieu de cela, si j'ai besoin de choses conditionnelles, je les mets dans des fonctions factorisées ou des macros factorisées; c'est beaucoup plus clair comme ça que je trouve (enfin, du moins c'est pour moi). Idéalement, toutes ces parties exclues seront dans d'autres fichiers (en-têtes ou fichiers sources compilés conditionnellement; la "condition" habituelle étant la plate-forme pour laquelle le code est construit).
Donal Fellows
2
Je mettrais en retrait les lignes 4 d'un niveau et les lignes 6 et 7 de deux niveaux.
Rocketmagnet le
3

Pour l'exemple que vous avez donné, il peut être approprié d'utiliser l'indentation pour le rendre plus clair, étant donné que vous avez une structure aussi complexe de directives imbriquées.

Personnellement, je pense qu'il est utile de les garder non indentés la plupart du temps, car ces directives fonctionnent séparément du reste de votre code. Les directives telles que #ifdef sont gérées par le pré-processeur, avant que le compilateur ne voie votre code, donc un bloc de code après une directive #ifdef peut même ne pas être compilé .

Garder les directives séparées visuellement du reste de votre code est plus important lorsqu'elles sont entrecoupées de code (plutôt que d'un bloc de directives dédié, comme dans l'exemple que vous donnez).

Daniel Fortunov
la source
3
Du point de vue de l'IP, quelle est la différence entre quelque chose qui n'est pas compilé et quelque chose qui n'est pas atteint à cause d'un jmp.
baash05
2

Je travaille actuellement dans un code qui contient un horrible mélange de #defines, #ifdefs, #elses, #endifs, #etc. Tout cela souvent mélangé avec du code C normal. La non-indentation des #defines les rend difficiles à lire. Et le mélange de code indenté avec des #defines non indentés est un cauchemar.

Une solution courante consiste à commenter les directives, afin de savoir facilement à quoi elles font référence:

#ifdef FOO
/* a lot of code */
#endif /* FOO */

#ifndef FOO
/* a lot of code */
#endif /* not FOO */
Bastien Léonard
la source
6
J'ai vu ce style, mon patron l'utilise. Et, comme le reste de son code, cela fait du désordre. Imaginez supprimer toutes les indentations de vos instructions if () normales et utiliser ces commentaires à la place. Vous vous plaindrez de ne pas voir facilement à quoi ils font référence.
Rocketmagnet le
2

Dans presque tous les compilateurs C / RPC actuellement disponibles, il n'est pas limité. C'est à l'utilisateur de décider comment vous souhaitez aligner le code. Si bon codage.

Hemanth
la source
1
Réponse décente. Pourriez-vous l'améliorer en ajoutant une référence spécifique au guide de style?
EtherDragon