Sangría #defines

8 minutos de lectura

avatar de usuario
Rocketmagnet

Yo sé eso #defines, etc. normalmente nunca tienen sangría. ¿Por qué?

Estoy trabajando en un código en este momento que tiene una mezcla horrible de #defines, #ifdefs, #elses, #endifs, etc. Todos estos a menudo se mezclan con el código C normal. La no sangría de la #defines los hace difíciles de leer. Y la mezcla de código sangrado con código no sangrado #defines es una pesadilla.

Por qué son #define¿Típicamente no tiene sangría? ¿Hay alguna razón por la que uno no sangraría (por ejemplo, como este código a continuación)?

#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

El preprocesador anterior a ANSI C no permitía espacios entre el comienzo de una línea y el carácter “#”; el “#” inicial tenía que colocarse siempre en la primera columna.

Los compiladores anteriores a ANSI C no existen en estos días. Utilice el estilo que prefiera (espacio antes de “#” o espacio entre “#” y el identificador).

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

avatar de usuario
patricio schlüter

Como algunos ya han dicho, algunos compiladores Pre-ANSI requerían que el # fuera el primer carácter en la línea, pero no requerían que se le adjuntara la directiva del preprocesador, por lo que la sangría se hizo de esta manera.

#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

A menudo he visto este estilo en encabezados antiguos de Unix, pero lo odio porque el coloreado de la sintaxis a menudo falla en dicho código. Utilizo un color muy visible para la directiva de preprocesador para que se destaquen (están en un metanivel, por lo que no deberían ser parte del flujo normal de código). Incluso puede ver que SO no colorea la secuencia de manera útil.

Con respecto al análisis sintáctico de las directivas del preprocesador, el estándar C99 (y el estándar C89 anterior) fueron claros acerca de la secuencia de operaciones realizadas lógicamente por el compilador. En particular, creo que significa que este código:

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

es equivalente a:

#include <stdio.h>

Para bien o para mal, GCC 3.4.4 con ‘-std=c89 -pedantic’ acepta la línea cargada de comentarios, en cualquier caso. No estoy defendiendo eso como un estilo, ni por un segundo (es espantoso). Solo creo que es posible.

ISO/IEC 9899:1999 sección 5.1.1.2 Fases de traducción dice:

  1. [Character mapping, including trigraphs]

  2. [Line splicing – removing backslash newline]

  3. El archivo de origen se descompone en tokens de preprocesamiento y secuencias de caracteres de espacio en blanco (incluidos los comentarios). Un archivo fuente no debe terminar en un token de preprocesamiento parcial o en un comentario parcial. Cada comentario se reemplaza por un carácter de espacio. Los caracteres de nueva línea se conservan. La implementación define si cada secuencia no vacía de caracteres de espacio en blanco que no sean de nueva línea se retiene o reemplaza por un carácter de espacio.

  4. Se ejecutan directivas de preprocesamiento, se expanden invocaciones de macros, […]

La sección 6.10 Directivas de preprocesamiento dice:

Una directiva de preprocesamiento consiste en una secuencia de tokens de preprocesamiento que comienza con un # token de preprocesamiento que (al comienzo de la fase 4 de traducción) es el primer carácter en el archivo fuente (opcionalmente después de un espacio en blanco que no contiene caracteres de nueva línea) o que sigue un espacio en blanco que contiene al menos un carácter de nueva línea y finaliza con el siguiente carácter de nueva línea.

La única disputa posible es la expresión entre paréntesis ‘(al comienzo de la fase 4 de traducción)’, lo que podría significar que los comentarios antes del hash deben estar ausentes ya que no se reemplazan por espacios hasta el final de la fase 4.

Como han señalado otros, los preprocesadores C anteriores al estándar no se comportaron de manera uniforme de varias maneras, y los espacios antes y en las directivas del preprocesador fueron una de las áreas en las que los diferentes compiladores hicieron cosas diferentes, incluido el no reconocer las directivas del preprocesador con espacios delante de ellas. .

Cabe señalar que la eliminación de la barra diagonal inversa se produce antes de que se analicen los comentarios. En consecuencia, no debe terminar // comentarios con una barra invertida.

No sé por qué no es más común. Ciertamente, hay momentos en los que me gusta sangrar las directivas del preprocesador.

Una cosa que sigue interponiéndose en mi camino (ya veces me convence de que deje de intentarlo) es que muchos o la mayoría de los editores/IDE arrojarán la directiva a la columna 1 a la menor provocación. Lo cual es molesto como el infierno.

En estos días creo que esto es principalmente una elección de estilo. I pensar en un momento del pasado lejano, no todos los compiladores admitían la noción de sangría de las definiciones del preprocesador. Investigué un poco y no pude respaldar esa afirmación. Pero en cualquier caso, parece que todos los compiladores modernos admiten la idea de sangrar la macro del preprocesador. Sin embargo, no tengo una copia del estándar C o C ++, por lo que no sé si este es un comportamiento estándar o no.

En cuanto a si es o no de buen estilo. Personalmente, me gusta la idea de mantenerlos todos a la izquierda. Le da un lugar consistente para buscarlos. Sí, puede volverse molesto cuando hay macros muy anidadas. Pero si los sangra, eventualmente terminará con un código de aspecto aún más extraño.

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

  • La razón por la que este código se ve extraño es porque ha creado dos “flujos” de sangría. Sangraría la línea 4 un nivel más, y sangraría las líneas 6 y 7 dos niveles más.

    –Kevin Laity

    15 de octubre de 2009 a las 20:58

  • Totalmente de acuerdo. A veces incluso pongo llaves para que los #si se vean como los si.

    – baash05

    10 de marzo de 2010 a las 5:21

  • Me esfuerzo mucho en organizar mi código para que tenga no #ifdef líneas en las partes donde tengo código real. En cambio, si necesito cosas condicionales, las pongo en funciones factorizadas o en macros factorizadas; es mucho más claro de esa manera que encuentro (bueno, al menos lo es para mí). Idealmente, todas esas partes eliminadas estarán en otros archivos (encabezados o archivos fuente compilados condicionalmente; la “condición” habitual es para qué plataforma se está creando el código).

    – Becarios Donal

    3 de julio de 2010 a las 9:09

  • Sangraría las líneas 4 un nivel y las líneas 6 y 7 dos niveles.

    – Rocketmagnet

    14/09/2010 a las 20:53

avatar de usuario
Daniel Fortunov

Para el ejemplo que ha dado, puede ser apropiado usar sangría para que quede más claro, ya que tiene una estructura tan compleja de directivas anidadas.

Personalmente, creo que es útil mantenerlas sin sangría la mayor parte del tiempo, porque estas directivas funcionan por separado del resto de su código. Las directivas como #ifdef son manejadas por el preprocesador, antes de que el compilador vea su código, por lo que un bloque de código después de una directiva #ifdef puede que ni siquiera sea compilado.

Mantener las directivas separadas visualmente del resto de su código es más importante cuando se intercalan con el código (en lugar de un bloque dedicado de directivas, como en el ejemplo que da).

  • La razón por la que este código se ve extraño es porque ha creado dos “flujos” de sangría. Sangraría la línea 4 un nivel más, y sangraría las líneas 6 y 7 dos niveles más.

    –Kevin Laity

    15 de octubre de 2009 a las 20:58

  • Totalmente de acuerdo. A veces incluso pongo llaves para que los #si se vean como los si.

    – baash05

    10 de marzo de 2010 a las 5:21

  • Me esfuerzo mucho en organizar mi código para que tenga no #ifdef líneas en las partes donde tengo código real. En cambio, si necesito cosas condicionales, las pongo en funciones factorizadas o en macros factorizadas; es mucho más claro de esa manera que encuentro (bueno, al menos lo es para mí). Idealmente, todas esas partes eliminadas estarán en otros archivos (encabezados o archivos fuente compilados condicionalmente; la “condición” habitual es para qué plataforma se está creando el código).

    – Becarios Donal

    3 de julio de 2010 a las 9:09

  • Sangraría las líneas 4 un nivel y las líneas 6 y 7 dos niveles.

    – Rocketmagnet

    14/09/2010 a las 20:53

En casi todos los compiladores C/CPP disponibles actualmente no está restringido. Depende del usuario decidir cómo desea alinear el código. Tan feliz codificación.

  • Respuesta decente. ¿Podría mejorarlo agregando alguna referencia de guía de estilo específica?

    – Ether Dragon

    21 de noviembre de 2019 a las 16:48

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad