O que exatamente um bloco #if 0… #endif faz?

124

Em C / C ++

O que acontece com o código colocado entre um bloco #if 0/ #endif?

#if 0

//Code goes here

#endif

O código simplesmente é ignorado e, portanto, não é executado?

vette982
fonte
17
Essa é uma técnica usada para comentar grandes quantidades de código ou para permitir o teste de inclusão de blocos de código. Sem esse recurso, seria necessário prefixar cada linha //ou iniciar a seção /*e terminar a seção com */. O problema com as últimas técnicas é que os comentários não são aninhados, portanto o desenvolvedor deve verificar e manipular qualquer um */entre o início e o fim.
Thomas Matthews

Respostas:

141

Não apenas ele não é executado, nem é compilado.

#ifé um comando de pré-processador, que é avaliado antes da etapa de compilação real. O código dentro desse bloco não aparece no binário compilado.

É frequentemente usado para remover temporariamente segmentos de código com a intenção de reativá-los mais tarde.

David
fonte
1
Isso vale para qualquer tipo de comentário. A diferença importante é o aninhamento.
Samy Bencherif
73

É idêntico a comentar o bloco, exceto com uma diferença importante: aninhar não é um problema. Considere este código:

foo();
bar(x, y); /* x must not be NULL */
baz();

Se quiser comentar, posso tentar:

/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/

Bzzt. Erro de sintaxe! Por quê? Como os comentários do bloco não são aninhados e, portanto (como você pode ver no destaque da sintaxe do SO)), */a palavra "NULL" finaliza o comentário, fazendo com que a bazchamada não seja comentada e o erro de sintaxe */após baz. Por outro lado:

#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif

Trabalha para comentar a coisa toda. E os n #if 0irão se aninhar, assim:

#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif

Embora, claro, isso possa ficar um pouco confuso e se tornar uma dor de cabeça de manutenção, se não for comentado adequadamente.

Tyler McHenry
fonte
5
Observe que o código dentro de #if deve estar lexicamente correto (ao contrário dos comentários) e as diretivas do pré-processador ainda estão em vigor (o mesmo).
jpalecek
@ David: Não é lexicamente correto, mas ainda será compilado. Portanto, o código não precisa estar lexicamente correto.
Dennis Zickefoose
1
@ Dennis, recebo foo.c:3: unterminated string or character constantdo gcc, o que você está usando?
David X
18

Ele comenta permanentemente esse código para que o compilador nunca o compile.

Mais tarde, o codificador pode alterar o #ifdef para compilar esse código no programa, se ele quiser.

É exatamente como o código não existe.

Nilbert
fonte
15

O que exatamente um bloco #if 0… #endif faz?

Ele diz que o autor obviamente nunca ouviu falar de um sistema de controle de versão. O que, por sua vez, diz para você fugir o mais longe possível…

Jörg W Mittag
fonte
12

Eu gostaria de adicionar para o #else caso:

#if 0
   /* Code here will NOT be complied. */
#else
   /* Code will be compiled. */
#endif


#if 1
   /* Code will be complied. */
#else
   /* Code will NOT be compiled. */
#endif
Steven Xu
fonte
7

Quando o pré-processador vê #if, verifica se o próximo token possui um valor diferente de zero. Se isso acontecer, ele mantém o código para o compilador. Caso contrário, ele se livra desse código para que o compilador nunca o veja.

Se alguém disser #if 0, estará efetivamente comentando o código para que nunca seja compilado. Você pode pensar nisso da mesma forma como se eles tivessem colocado / * ... * / em torno dele. Não é exatamente o mesmo, mas tem o mesmo efeito.

Se você quiser entender o que aconteceu em detalhes, pode procurar com frequência. Muitos compiladores permitem ver os arquivos após a execução do pré-processador. Por exemplo, no Visual C ++, o comando switch / P executará o pré-processador e colocará os resultados em um arquivo .i.

Steve Rowe
fonte
Não é bem assim. O pré-processador analisa por linha e não por token. De acordo com sua explicação, não seria possível dizer, por exemplo, #if WIN32 || __CYGWIN__mas isso funciona como esperado.
Ben Voigt
Eu estava simplificando. Se houver um ou, ele verificará se um token é diferente de zero. Da mesma forma, se houver um e ele verificará se ambos são diferentes de zero.
Steve Rowe
3

Linhas começando com a #são diretivas de pré-processador . #if 0 [...] #endifblocos não chegam ao compilador e não geram código de máquina.

Você pode demonstrar o que acontece com o pré-processador com um arquivo de origem ifdef.cxx:

#if 0
This code will not be compiled
#else
int i = 0;
#endif

Corrida gcc -E ifdef.cxx mostrará o que é compilado.

Você pode optar por usar esse mecanismo para impedir que um bloco de código seja compilado durante o ciclo de desenvolvimento, mas provavelmente não deseja fazer check-in no controle de origem, pois apenas adiciona fragmentos ao código e reduz a legibilidade. Se um comentário histórico foi comentado, ele deve ser removido: o controle de origem contém o histórico, certo?

Além disso, a resposta pode ser a mesma para C e C ++, mas não existe uma linguagem chamada C / C ++ e não é um bom hábito referir-se a essa linguagem.

Johnsyweb
fonte
4
O que há de errado em dizer C / C ++ como abreviação de "C or C ++"? Você honestamente acha que alguém ficará confuso ao pensar que existe uma linguagem chamada "C / C ++"?
Christopher Barber
1
@ Chris: As pessoas constantemente fazem perguntas como "Como faço para X em C / C ++?" Qual é uma pergunta sem sentido; você está codificando um ou outro e, se ainda não escolheu, deve ser explícito nesse fato. Então, sim, as pessoas estão confusas sobre a existência de uma linguagem chamada "C / C ++"
Dennis Zickefoose
1
Que afirmação absurda! Existem milhares de perguntas cujas respostas são relevantes para C e C ++. Lembre-se de que este é um site para perguntas. Só porque você está fazendo uma pergunta geral, não significa que você não sabe o idioma que está usando. Se você suspeita que seja esse o caso, como nesta pergunta, como isso ajuda a especificar C ou C ++? Você acha que seria útil se todas as perguntas que pudessem ser aplicadas em C ou C ++ fossem feitas duas vezes?
Christopher Barber
@ Christopher: Você está certo, há muitas perguntas em que as respostas são igualmente relevantes para C, C ++ e Objective-C (sendo esta uma delas). O Stack Overflow possui um prático sistema de marcação para indicar a quais idiomas uma pergunta pertence. Como o @Dennis menciona, SO (e outros fóruns de programação [??]) Há (também) muitas pessoas que estão confusas quanto ao delineamento entre C e outras linguagens derivadas de C que se referem a essas linguagens de maneira intercambiável como C / C ++ mais difícil responder à pergunta no idioma apropriado.
Johnsyweb
2

Não exatamente

int main(void)
{
   #if 0
     the apostrophe ' causes a warning
   #endif
   return 0;
}

Ele mostra "tc: 4: 19: aviso: 'caractere final ausente" com o gcc 4.2.4

Arthur Kalliokoski
fonte
2
Esse aviso é gerado pelo pré-processador, não pelo compilador. O compilador apenas vê: # 1 "tc" # 1 "<built-in>" # 1 "<comand-line>" # 1 "tc" int main (void) {return 0; }
Johnsyweb
0

É uma maneira barata de comentar, mas suspeito que possa ter um potencial de depuração. Por exemplo, vamos supor que você tenha uma construção que produza valores para um arquivo. Você pode não querer isso em uma versão final para poder usar o #if 0 ... #endif.

Além disso, suspeito que uma maneira melhor de fazê-lo para fins de depuração seria:

#ifdef DEBUG
// output to file
#endif

Você pode fazer algo assim e pode fazer mais sentido e tudo o que você precisa fazer é definir DEBUG para ver os resultados.

Daniel
fonte