web-dev-qa-db-fra.com

Retrait #defines

Je sais que #define, Etc. ne sont normalement jamais en retrait. Pourquoi?

Je travaille actuellement sur un code qui a un mélange horrible de #define S, #ifdef S, #else S, #endif S, etc. Tous ces éléments sont souvent mélangés au code C normal. La non-indentation des #define Les rend difficiles à lire. Et le mélange de code en retrait et de #define S sans retrait est un cauchemar.

Quel est l'avantage de ne pas mettre en retrait #define S? Cela fait-il 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
94
Rocketmagnet

Le préprocesseur pré-ANSI C ne permettait pas d'espace entre le début d'une ligne et le caractère "#"; le "#" de tête 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

98
anon

Comme certains l'ont déjà dit, certains compilateurs pré-ANSI exigeaient que le # soit le premier caractère sur la ligne mais ils ne nécessitaient pas de directive de préprocesseur pour y être attachés, 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 du 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.

24
Patrick Schlüter

En ce qui concerne l'analyse des directives de préprocesseur, la norme C99 (et la norme C89 avant elle) était claire quant à la séquence des 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 la ligne chargée de commentaires, en tout cas. Je ne préconise pas cela comme style - pas une seconde (c'est horrible). Je pense juste que c'est possible.

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

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

  2. [Épissage de ligne - suppression de la nouvelle ligne antislash]

  3. Le fichier source est décomposé en jetons de prétraitement et séquences de caractères d'espaces blancs (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. 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 invocations de macros sont développées, [...]

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 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 façons, et les espaces avant et dans les directives de préprocesseur étaient l'un des domaines où différents compilateurs faisaient des choses différentes, y compris la non-reconnaissance des directives de préprocesseur avec des espaces devant eux. .

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

16
Jonathan Leffler

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

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

6
Michael Burr

De nos jours, je crois que c'est principalement un choix de style. I pensez à un moment donné dans un passé lointain, tous les compilateurs n'ont pas pris en charge la notion de définition du préprocesseur en retrait. J'ai fait des recherches et je n'ai pas pu confirmer cette affirmation. Mais dans tous les cas, il semble que tous les compilateurs modernes prennent en charge l'idée de mettre en retrait la macro du pré-processeur. Je n'ai pas de copie de la norme C ou C++, donc je ne sais pas si c'est un comportement standard ou non.

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

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif
5
JaredPar

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 si complexe de directives imbriquées.

Personnellement, je pense qu'il est utile de ne pas les mettre en retrait 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 visuellement séparées 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).

3
Daniel Fortunov

Je travaille actuellement sur un code qui a un horrible mélange de #defines, #ifdefs, #elses, #endifs, #etc. Tous ces éléments sont souvent mélangés au code C normal. La non-indentation des #defines les rend difficiles à lire. Et le mélange de code indenté et de # définitions non indentées est un cauchemar.

Une solution courante consiste à commenter les directives, afin que vous sachiez facilement à quoi elles se réfèrent:

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

#ifndef FOO
/* a lot of code */
#endif /* not FOO */
2
Bastien Léonard