Isso pode ser uma questão de estilo, mas há um pouco de divisão em nossa equipe de desenvolvimento e eu me pergunto se mais alguém tem alguma idéia sobre o assunto ...
Basicamente, temos algumas instruções de impressão de depuração que desativamos durante o desenvolvimento normal. Pessoalmente, prefiro fazer o seguinte:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Alguns membros da equipe preferem o seguinte:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
... qual desses métodos soa melhor para você e por quê? Minha sensação é que o primeiro é mais seguro porque sempre há algo definido e não há perigo de que possa destruir outras definições em outro lugar.
c++
c
if-statement
coding-style
c-preprocessor
Jon Cage
fonte
fonte
#if
, você também pode usar de#elif
maneira consistente, ao contrário de#ifdef
. Assim, em vez de apenas usar#define BLAH
, use#define BLAH 1
com#if BLAH
, etc ...Respostas:
Minha reação inicial foi
#ifdef
, é claro , mas acho que#if
realmente tem algumas vantagens significativas para isso - aqui está o motivo:Primeiro, você pode usar
DEBUG_ENABLED
em testes de pré - processador e compilados. Exemplo - Freqüentemente, desejo tempos limite mais longos quando a depuração está habilitada, então usando#if
, posso escrever isso... ao invés de ...
Em segundo lugar, você está em uma posição melhor se quiser migrar de uma
#define
constante para uma global.#define
s geralmente são desaprovados pela maioria dos programadores C ++.E, terceiro, você diz que tem uma divisão em sua equipe. Meu palpite é que isso significa que membros diferentes já adotaram abordagens diferentes e você precisa padronizar. Decidir que
#if
é a escolha preferida significa que o código usando#ifdef
irá compilar - e executar - mesmo quandoDEBUG_ENABLED
for falso. E é muito mais fácil rastrear e remover a saída de depuração produzida quando não deveria ser do que vice-versa.Ah, e um pequeno ponto de legibilidade. Você deve ser capaz de usar verdadeiro / falso em vez de 0/1 no seu
#define
e, como o valor é um único token léxico, é o único momento em que você não precisa de parênteses em volta dele.ao invés de
fonte
#ifdef
é que funciona com coisas que não estão definidas; se eles não foram definidos intencionalmente ou por causa de um erro de digitação ou o que quer que seja.#if DEBUG_ENBALED
não é um erro detectado pelo pré-processador. SeDEBUG_ENBALED
não for definido, ele se expande para o token0
nas#if
diretivas.Ambos são horríveis. Em vez disso, faça o seguinte:
Então, sempre que você precisar do código de depuração, coloque-o dentro
D();
. E seu programa não está poluído com horríveis labirintos de#ifdef
.fonte
#ifdef
apenas verifica se um token está definido, dadoentão
fonte
Tivemos esse mesmo problema em vários arquivos e sempre há o problema de as pessoas se esquecerem de incluir um arquivo de "sinalizador de recursos" (com uma base de código de> 41.000 arquivos é fácil fazer).
Se você tivesse feature.h:
Mas então você se esqueceu de incluir o arquivo de cabeçalho em file.cpp:
Então você tem um problema, o compilador interpreta COOL_FEATURE sendo indefinido como um "falso" neste caso e falha em incluir o código. Sim, o gcc suporta um sinalizador que causa um erro para macros indefinidas ... mas a maioria dos códigos de terceiros define ou não define recursos, portanto, não seria tão portátil.
Adotamos uma maneira portátil de corrigir este caso, bem como testar o estado de um recurso: macros de função.
se você alterou o feature.h acima para:
Mas, novamente, você se esqueceu de incluir o arquivo de cabeçalho em file.cpp:
O pré-processador teria dado um erro devido ao uso de uma macro de função indefinida.
fonte
Para fins de compilação condicional, #if e #ifdef são quase iguais, mas não exatamente. Se sua compilação condicional depender de dois símbolos, #ifdef não funcionará bem. Por exemplo, suponha que você tenha dois símbolos de compilação condicional, PRO_VERSION e TRIAL_VERSION, você pode ter algo assim:
Usar #ifdef acima se torna muito mais complicado, especialmente fazer a parte #else funcionar.
Trabalho com código que usa extensivamente a compilação condicional e temos uma mistura de #if e #ifdef. Temos a tendência de usar # ifdef / # ifndef para o caso simples e #if sempre que dois ou mais símbolos estão sendo avaliados.
fonte
#if defined
que édefined
uma palavra-chave ou?Acho que é inteiramente uma questão de estilo. Nenhum deles tem uma vantagem óbvia sobre o outro.
A consistência é mais importante do que qualquer escolha em particular, então eu recomendo que você se reúna com sua equipe e escolha um estilo, e se atenha a ele.
fonte
Eu mesmo prefiro:
Uma vez que torna mais fácil criar um código que procure a condição oposta, muito mais fácil de detectar:
vs.
fonte
#if ! defined
para tornar o!
mais proeminente e difícil de perder.É uma questão de estilo. Mas recomendo uma maneira mais concisa de fazer isso:
Você faz isso uma vez, então sempre usa debug_print () para imprimir ou não fazer nada. (Sim, isso será compilado em ambos os casos.) Dessa forma, seu código não será distorcido com as diretivas do pré-processador.
Se você receber o aviso "a expressão não tem efeito" e quiser se livrar dela, aqui está uma alternativa:
fonte
#if
oferece a opção de defini-lo como 0 para desligar a funcionalidade, enquanto ainda detecta que a chave está lá.Pessoalmente, eu sempre
#define DEBUG 1
posso pegá-lo com um #if ou #ifdeffonte
#define DEBUG 1
. Não#define DEBUG=1
#if e #define MY_MACRO (0)
Usar #if significa que você criou uma macro "definir", ou seja, algo que será pesquisado no código para ser substituído por "(0)". Este é o "inferno da macro" que odeio ver em C ++, porque polui o código com possíveis modificações de código.
Por exemplo:
dá o seguinte erro no g ++:
Apenas um erro.
O que significa que sua macro interagiu com sucesso com seu código C ++: A chamada para a função foi bem-sucedida. Neste caso simples, é divertido. Mas minha própria experiência com macros brincando silenciosamente com meu código não é cheia de alegria e realização, então ...
#ifdef e #define MY_MACRO
Usar #ifdef significa que você "define" algo. Não que você dê um valor. Ainda é poluente, mas pelo menos será "substituído por nada" e não será visto pelo código C ++ como uma instrução de código lagitima. O mesmo código acima, com uma definição simples, ele:
Dá os seguintes avisos:
Assim...
Conclusão
Prefiro viver sem macros em meu código, mas por vários motivos (definir protetores de cabeçalho ou macros de depuração), não posso.
Mas, pelo menos, gosto de torná-los o menos interativos possível com meu código C ++ legítimo. O que significa usar #define sem valor, usando #ifdef e #ifndef (ou mesmo #if definido como sugerido por Jim Buck) e, acima de tudo, dando-lhes nomes tão longos e tão estranhos que ninguém em sã consciência usará isso "por acaso", e de forma alguma afetará o código C ++ legítimo.
Post Scriptum
Agora, enquanto relendo meu post, me pergunto se não devo tentar encontrar algum valor que jamais será C ++ correto para adicionar à minha definição. Algo como
que poderia ser usado com #ifdef e #ifndef, mas não deixe o código compilar se usado dentro de uma função ... Eu tentei isso com sucesso no g ++ e deu o erro:
Interessante. :-)
fonte
Isso não é uma questão de estilo. Além disso, a pergunta está infelizmente errada. Você não pode comparar essas diretivas de pré-processador no sentido de melhor ou mais seguro.
significa "se a macro for definida" ou "se a macro existir". O valor da macro não importa aqui. Pode ser qualquer coisa.
se sempre comparar a um valor. No exemplo acima, é a comparação implícita padrão:
exemplo para o uso de #if
agora você pode colocar a definição de CFLAG_EDITION em seu código
ou você pode definir a macro como sinalizador do compilador. Veja também aqui .
fonte
O primeiro parece mais claro para mim. Parece mais natural torná-lo um sinalizador em comparação com definido / não definido.
fonte
Ambos são exatamente equivalentes. No uso idiomático, #ifdef é usado apenas para verificar a definição (e o que eu usaria em seu exemplo), enquanto #if é usado em expressões mais complexas, como #if definido (A) &&! Definido (B).
fonte
Um pouco OT, mas ligar / desligar o registro com o pré-processador é definitivamente abaixo do ideal em C ++. Existem boas ferramentas de registro, como o log4cxx do Apache, que são de código aberto e não restringem como você distribui seu aplicativo. Eles também permitem que você altere os níveis de registro sem recompilação, têm sobrecarga muito baixa se você desligar o registro e lhe dão a chance de desligar completamente o registro na produção.
fonte
Eu costumava usar
#ifdef
, mas quando mudei para Doxygen para documentação, descobri que macros comentadas não podem ser documentadas (ou, pelo menos, Doxygen produz um aviso). Isso significa que não posso documentar as macros de alternância de recursos que não estão ativadas no momento.Embora seja possível definir as macros apenas para Doxygen, isso significa que as macros nas partes não ativas do código também serão documentadas. Pessoalmente, quero mostrar as opções de recurso e, caso contrário, apenas documentar o que está selecionado no momento. Além disso, torna o código bastante confuso se houver muitas macros que precisam ser definidas apenas quando o Doxygen processa o arquivo.
Portanto, neste caso, é melhor sempre definir as macros e usar
#if
.fonte
Sempre usei #ifdef e sinalizadores de compilador para defini-lo ...
fonte
Como alternativa, você pode declarar uma constante global e usar o C ++ if, em vez do pré-processador #if. O compilador deve otimizar os branches não usados para você, e seu código ficará mais limpo.
Aqui está o que C ++ Gotchas de Stephen C. Dewhurst diz sobre o uso de # if's.
fonte
Há uma diferença no caso de uma maneira diferente de especificar uma definição condicional para o driver:
resultado:
Isso significa que
-DA
é sinônimo de-DA=1
e se o valor for omitido, pode haver problemas no caso de#if A
uso.fonte
Gosto
#define DEBUG_ENABLED (0)
quando você deseja vários níveis de depuração. Por exemplo:Torna mais fácil depurar vazamentos de memória, sem ter todas essas linhas de log em sua maneira de depurar outras coisas.
Além disso, a
#ifndef
definição ao redor torna mais fácil escolher um nível de depuração específico na linha de comando:Se não fosse por isso, eu daria vantagem
#ifdef
porque o sinalizador compilador / make seria substituído pelo sinalizador do arquivo. Então você não precisa se preocupar em mudar de volta o cabeçalho antes de fazer o commit.fonte