Indentação # define

99

Eu sei disso #define s, etc. normalmente nunca são indentados. Por quê?

Estou trabalhando em algum código no momento que tem uma mistura horrível de #defines, #ifdefs, #elses, #endifs, etc. Tudo isso geralmente misturado com o código C normal. O não recuo do #defines torna-os difíceis de ler. E a mistura de código indentado com #defines não indentado é um pesadelo.

Qual é a vantagem de não recuar #defines? Isso me torna uma pessoa má se eu identificá-los? Não é muito melhor?

#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
fonte

Respostas:

103

O pré-processador pré-ANSI C não permitia espaço entre o início de uma linha e o caractere "#"; o "#" inicial sempre deveria ser colocado na primeira coluna.

Compiladores pré-ANSI C não existem atualmente. Use qualquer estilo (espaço antes de "#" ou espaço entre "#" e o identificador) de sua preferência.

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


fonte
26

Como alguns já disseram, alguns compiladores Pré-ANSI exigiam que o # fosse o primeiro caractere da linha, mas não exigiam que a diretiva do pré-processador fosse anexada a ele, então a indentação foi feita dessa forma.

#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

Eu sempre vi esse estilo em cabeçalhos Unix antigos, mas eu odeio isso, pois a coloração da sintaxe geralmente falha nesse código. Eu uso uma cor muito visível para a diretiva do pré-processador para que eles se destaquem (eles estão em um meta-nível, então não devem fazer parte do fluxo normal de código). Você pode até ver que o SO não colore a sequência de uma maneira útil.

Patrick Schlüter
fonte
16

Com relação à análise das diretivas do pré-processador, o padrão C99 (e o padrão C89 antes dele) eram claros sobre a seqüência de operações realizadas logicamente pelo compilador. Em particular, acredito que significa que este código:

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

é equivalente a:

#include <stdio.h>

Para melhor ou pior, o GCC 3.4.4 com '-std = c89 -pedantic' aceita a linha de comentários carregados, de qualquer forma. Não estou defendendo isso como um estilo - nem por um segundo (é horrível). Só acho que é possível.

ISO / IEC 9899: 1999 seção 5.1.1.2 Fases de tradução diz:

  1. [Mapeamento de caracteres, incluindo trígrafos]

  2. [Linha de emenda - removendo barra invertida de nova linha]

  3. O arquivo de origem é decomposto em tokens de pré-processamento e sequências de caracteres de espaço em branco (incluindo comentários). Um arquivo de origem não deve terminar em um token de pré-processamento parcial ou em um comentário parcial. Cada comentário é substituído por um caractere de espaço. Os caracteres de nova linha são mantidos. Se cada sequência não vazia de caracteres de espaço em branco diferente de nova linha for mantida ou substituída por um caractere de espaço, é definido pela implementação.

  4. As diretivas de pré-processamento são executadas, as invocações de macro são expandidas, [...]

A seção 6.10 Diretrizes de pré-processamento diz:

Uma diretiva de pré-processamento consiste em uma sequência de tokens de pré-processamento que começa com um # token de pré-processamento que (no início da fase de tradução 4) é o primeiro caractere do arquivo de origem (opcionalmente após o espaço em branco sem caracteres de nova linha) ou que segue o espaço em branco contendo pelo menos um caractere de nova linha e é finalizado pelo próximo caractere de nova linha.

A única disputa possível é a expressão entre parênteses '(no início da fase 4 de tradução)', o que poderia significar que os comentários antes do hash devem estar ausentes, uma vez que não são substituídos por espaços até o final da fase 4.

Como outros notaram, os pré-processadores C pré-padrão não se comportavam uniformemente de várias maneiras, e os espaços antes e nas diretivas do pré-processador era uma das áreas em que diferentes compiladores faziam coisas diferentes, incluindo o não reconhecimento de diretivas de pré-processador com espaços à frente deles .

É digno de nota que a remoção da barra invertida-nova linha ocorre antes de os comentários serem analisados. Conseqüentemente, você não deve terminar os //comentários com uma barra invertida.

Jonathan Leffler
fonte
7

Não sei porque não é mais comum. Certamente há momentos em que gosto de indentar as diretivas do pré-processador.

Uma coisa que continua me atrapalhando (e às vezes me convence a parar de tentar) é que muitos ou a maioria dos editores / IDEs vão lançar a diretiva para a coluna 1 à menor provocação. O que é irritante pra caramba.

Michael Burr
fonte
5

Hoje em dia, acredito que isso seja principalmente uma escolha de estilo. Eu acho em um ponto no passado distante, nem todos os compiladores suportavam a noção de indentação de definições de pré-processador. Eu fiz algumas pesquisas e não fui capaz de confirmar essa afirmação. Mas, em qualquer caso, parece que todos os compiladores modernos apóiam a ideia de recuar macro de pré-processador. Eu não tenho uma cópia do padrão C ou C ++, então não sei se esse é o comportamento padrão ou não.

Quanto ao estilo ou não. Pessoalmente, gosto da ideia de mantê-los todos à esquerda. Dá a você um lugar consistente para procurá-los. Sim, pode ser irritante quando há macros muito aninhadas. Mas se você recuá-los, acabará ficando com um código ainda mais estranho.

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif
JaredPar
fonte
14
A razão deste código parecer estranho é porque você criou dois "fluxos" de indentação. Eu recuaria a linha 4 em mais um nível e as linhas 6 e 7 em mais dois níveis.
Kevin Laity,
3
Concordo plenamente. Às vezes até coloco colchetes para que os # se fiquem parecidos com os se.
baash05
3
Tento muito organizar meu código de modo que não haja #ifdef linhas nas partes em que tenho o código real. Em vez disso, se preciso de coisas condicionais, coloco-as em funções fatoradas ou em macros fatoradas; é muito mais claro assim que eu acho (bem, pelo menos é para mim). Idealmente, todas essas partes fatoradas estarão em outros arquivos (cabeçalhos ou arquivos de origem compilados condicionalmente; a "condição" usual é a plataforma para a qual o código está sendo construído).
Donal Fellows
2
Eu recuaria as linhas 4 em um nível e as linhas 6 e 7 em dois níveis.
Rocketmagnet
3

Para o exemplo que você deu, pode ser apropriado usar recuo para torná-lo mais claro, visto que você tem uma estrutura complexa de diretivas aninhadas.

Pessoalmente, acho útil mantê-los sem recuo na maioria das vezes, porque essas diretivas operam separadamente do resto do código. Diretivas como #ifdef são tratadas pelo pré-processador, antes que o compilador veja seu código, então um bloco de código após uma diretiva #ifdef pode nem mesmo ser compilado .

Manter as diretivas visualmente separadas do resto do código é mais importante quando elas são intercaladas com o código (em vez de um bloco dedicado de diretivas, como no exemplo que você fornece).

Daniel Fortunov
fonte
3
Do ponto de vista do IP, qual é a diferença entre algo que não está compilado e algo que não é alcançado por causa de um jmp.
baash05
2

Estou trabalhando em um código no momento que tem uma mistura horrível de #defines, #ifdefs, #elses, #endifs, #etc. Todos estes frequentemente misturados com o código C normal. O não recuo de # define torna-os difíceis de ler. E a mistura de código indentado com #defines não indentado é um pesadelo.

Uma solução comum é comentar as diretivas, para que você saiba facilmente a que se referem:

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

#ifndef FOO
/* a lot of code */
#endif /* not FOO */
Bastien Léonard
fonte
6
Eu vi esse estilo, meu chefe usa. E, como o resto de seu código, só faz uma bagunça. Imagine remover todo o recuo de suas instruções if () normais e usar esses comentários em seu lugar. Você reclamará que não consegue ver facilmente a que se referem.
Rocketmagnet
2

Em quase todos os compiladores C / CPP disponíveis atualmente, ele não é restrito. Cabe ao usuário decidir como deseja alinhar o código. Tão feliz com codificação.

Hemanth
fonte
1
Resposta decente. Você poderia melhorá-lo adicionando alguma referência específica ao guia de estilo?
EtherDragon