Será que os C comentários tira pré-processador ou expandir macros em primeiro lugar? [duplicado]

StackOverflow https://stackoverflow.com/questions/1510869

Pergunta

Esta questão já tem uma resposta aqui:

Considere isso (horrível, terrível, não é bom, muito ruim) estrutura de código:

#define foo(x) // commented out debugging code

// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);

Eu vi preprocessors dois compiladores gerar resultados diferentes sobre este código:

if (a)
bar(a);

e

if (a)
;
bar(a);

Obviamente, isso é uma coisa ruim para uma base de código portátil.

A minha pergunta: O que é o pré-processador deveria fazer com isso? Elide comenta em primeiro lugar, ou expandir macros primeiro?

Foi útil?

Solução

Infelizmente, o original ANSI C Especificação especificamente exclui qualquer Preprocessor apresenta na seção 4 ( "Esta especificação descreve apenas a linguagem C. Ele não prevê qualquer biblioteca ou o pré-processador.").

O C99 especificação lida com isso explicitamente , Apesar. Os comentários são substituídos por um único espaço na "fase de tradução", que acontece antes da análise directiva pré-processamento. (Seção 6.10 para mais detalhes).

VC ++ e GNU C Compiler ambos seguem este paradigma - outros compiladores podem não ser compatíveis se eles 're mais velhos, mas se é compatível com C99, você deve ser seguro.

Outras dicas

Como descrito no esta cópia-n-colada decription das fases de tradução no padrão C99, removendo comentários (eles são substituídos por um único espaço em branco) ocorre em fase de tradução 3, enquanto as directivas de pré-processamento são tratadas e as macros são expandidas na fase 4.

No padrão C90 (que só tem em cópia dura, de modo que nenhuma cópia-n-cole) estas duas fases ocorrem na mesma ordem, embora a descrição das fases de tradução é ligeiramente diferente em alguns detalhes do padrão C99 -. o fato de que os comentários são removidos e substituídos por um único espaço em branco antes de pré-processamento diretivas são manipulados e macros expandido não é diferente

De novo, o padrão C ++ tem estes 2 fases ocorrem na mesma ordem.

Com relação a como os comentários dos // 'deve ser manuseado, o padrão C99 diz isso (6.4.9 / 2):

exceto dentro uma constante personagem, um literal string, ou um comentário, os caracteres // introduzir um comentário que inclui todos os caracteres de vários bytes até, mas não incluindo, a próximo caractere de nova linha.

E o padrão C ++ diz (2.7):

Os caracteres // iniciar um comentário, que termina com o final da linha caráter.

Portanto, o seu primeiro exemplo é claramente um erro por parte desse tradutor - o personagem ';' após a foo(a) deve ser mantida quando a macro foo() é expandido - os caracteres de comentário não deve ser parte dos 'conteúdos' de the foo() macro.

Mas desde que você se depara com um tradutor de buggy, você pode querer mudar a definição de macro para:

#define foo(x) /* junk */

Para resolver o bug.

No entanto (e eu estou à deriva fora de tópico aqui ...), desde linha de splicing (barras invertidas antes de uma nova linha) ocorre antes dos comentários são processados, você pode executar em algo como este pedaço de código desagradável:

#define evil( x) printf( "hello "); // hi there, \
                 printf( "%s\n", x); // you!



int main( int argc, char** argv)
{
    evil( "bastard");

    return 0;
}

O que pode surpreender quem a escreveu.

Ou melhor ainda, tente o seguinte, escrito por alguém que gosta de comentários no estilo caixa (certamente não me!):

int main( int argc, char** argv)
{
                            //----------------/
    printf( "hello ");      // Hey, what the??/
    printf( "%s\n", "you"); // heck??         /
                            //----------------/
    return 0;
}

Dependendo se o padrão de compilador para processamento trigraphs ou não (compiladores é suposto, mas desde trigraphs surpreender quase todos que atravessa eles, alguns compiladores decidir desligá-los por padrão), você pode ou não pode obter o comportamento desejado -. qualquer comportamento que é, naturalmente

De acordo com a MSDN , os comentários são substituídos com um único espaço na fase tokenization, que acontece antes da fase de pré-processamento, onde as macros são expandidas.

Nunca coloque // comentários em suas macros. Se você deve colocar comentários, use / * * /. Além disso, você tem um erro em sua macro:

#define foo(x) do { } while(0) /* junk */

Desta forma, foo é sempre mais seguro para usar. Por exemplo:

if (some condition)
    foo(x);

nunca vai lançar um erro do compilador, independentemente de haver ou não foo é definida a alguma expressão.

#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr / ## / cerr
#endif
  • irá funcionar em alguns compiladores (VC ++). Quando _TEST_ não está definido,

    _cerr ...

    será substituído pela linha de comentário

    // cerr ...

Se bem me lembro que o cumprimento requer três etapas:

  1. tira
  2. expandir macros
  3. tira novamente

A razão para isto tem a ver com o compilador ser capaz de aceitar .i arquivos diretamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top