Existe alguma opinião sobre se usar o #define para definir linhas completas de código para simplificar a codificação é uma boa ou má prática de programação? Por exemplo, se eu precisasse imprimir um monte de palavras, ficaria irritado digitando
<< " " <<
Para inserir um espaço entre as palavras em uma instrução cout. Eu poderia fazer
#define pSpace << " " <<
e tipo
cout << word1 pSpace word2 << endl;
Para mim, isso não adiciona ou subtrai a clareza do código e facilita a digitação. Há outros casos em que consigo pensar em que a digitação será muito mais fácil, geralmente para depuração.
Alguma idéia sobre isso?
EDIT: Obrigado por todas as ótimas respostas! Essa pergunta surgiu depois de muita digitação repetitiva, mas nunca pensei que houvesse outras macros menos confusas para usar. Para aqueles que não desejam ler todas as respostas, a melhor alternativa é usar as macros do seu IDE para reduzir a digitação repetitiva.
fonte
Respostas:
Escrever código é fácil. Ler código é difícil.
Você escreve o código uma vez. Ele vive há anos, as pessoas leem centenas de vezes.
Otimize o código para leitura, não para escrita.
fonte
Pessoalmente, eu detesto isso. Há várias razões pelas quais desencorajo as pessoas dessa técnica:
No tempo de compilação, as alterações reais do código podem ser significativas. O próximo cara aparece e até inclui um colchete em seu #define ou uma chamada de função. O que está escrito em um determinado ponto do código está longe do que estará disponível após o pré-processamento.
É ilegível. Pode ficar claro para você .. por enquanto .. se é apenas essa definição. Se isso se tornar um hábito, você acabará em breve com dezenas de #defines e começará a perder o controle. Mas o pior de tudo é que ninguém mais será capaz de entender o que
word1 pSpace word2
exatamente significa (sem consultar o #define).Pode se tornar um problema para ferramentas externas. Digamos que você de alguma forma termine com um #define que inclui um colchete de fechamento, mas sem colchete de abertura. Tudo pode funcionar bem, mas editores e outras ferramentas podem parecer algo
function(withSomeCoolDefine;
bastante peculiar (ou seja, eles relatam erros e outros enfeites). (Exemplo semelhante: uma chamada de função dentro de um define - suas ferramentas de análise poderão encontrar essa chamada?)A manutenção se torna muito mais difícil. Você define tudo isso além dos problemas usuais que a manutenção traz consigo. Além do ponto acima, o suporte da ferramenta para refatoração também pode ser afetado negativamente.
fonte
Meu principal pensamento sobre isso é que eu nunca uso "facilitar a digitação" como regra ao escrever código.
Minha regra principal ao escrever um código é torná-lo facilmente legível. A lógica por trás disso é simplesmente que o código é lido uma ordem de magnitude mais vezes do que é escrito. Dessa forma, o tempo que você perde escrevendo-o com cuidado, em ordem e com disposição correta, é de fato investido em fazer mais leituras e entender muito mais rapidamente.
Dessa forma, o #define que você usa simplesmente quebra a maneira usual de alternância
<<
e outras coisas . Ele quebra a regra da menor surpresa e não é uma coisa boa.fonte
Esta pergunta fornece um exemplo claro de como você pode usar mal as macros. Para ver outros exemplos (e se divertir), veja esta pergunta .
Dito isso, darei exemplos do mundo real do que considero uma boa incorporação de macros.
O primeiro exemplo aparece no CppUnit , que é uma estrutura de teste de unidade. Como qualquer outra estrutura de teste padrão, você cria uma classe de teste e precisa especificar, de alguma forma, quais métodos devem ser executados como parte do teste.
Como você pode ver, a classe possui um bloco de macros como seu primeiro elemento. Se eu adicionei um novo método
testSubtraction
, é óbvio o que você precisa fazer para incluí-lo no teste.Esses blocos de macro se expandem para algo assim:
Qual você prefere ler e manter?
Outro exemplo está na estrutura do Microsoft MFC, onde você mapeia funções para mensagens:
Então, quais são as coisas que distinguem "Boas Macros" do tipo maligno horrível?
Eles executam uma tarefa que não pode ser simplificada de nenhuma outra maneira. Escrever uma macro para determinar o máximo entre dois elementos está errado, porque você pode obter o mesmo usando um método de modelo. Mas existem algumas tarefas complexas (por exemplo, mapear códigos de mensagens para funções-membro) com as quais a linguagem C ++ simplesmente não lida com elegância.
Eles têm um uso formal extremamente rigoroso. Nos dois exemplos, os blocos de macro são anunciados iniciando e finalizando macros, e as macros entre elas só aparecerão dentro desses blocos. Você tem C ++ normal, se desculpa brevemente com um bloco de macros e volta ao normal novamente. Nos exemplos de "macros malignas", as macros estão espalhadas por todo o código e o infeliz leitor não tem como saber quando as regras do C ++ se aplicam e quando não.
fonte
Será, de todo modo, melhor se você ajustar seu editor de texto / IDE favorito para inserir trechos de código que você achar cansativo redigitar novamente. E melhor é o termo "educado" para comparação. Na verdade, não consigo pensar em nenhum caso semelhante ao pré-processar as macros do editor. Bem, pode ser um - quando, por algumas razões misteriosas e infelizes, você estiver constantemente usando diferentes conjuntos de ferramentas para codificação. Mas não é uma justificativa :)
Também pode ser uma solução melhor para cenários mais complexos, quando o pré-processamento de texto pode fazer coisas muito mais ilegíveis e complicadas (pense em entradas parametrizadas).
fonte
<< " " <<
.Os outros já explicaram por que você não deve fazê-lo. Seu exemplo obviamente não merece ser implementado com uma macro. Mas, há uma grande variedade de casos em que você tem usar macros para facilitar a leitura.
Um exemplo notório de uma aplicação inteligente dessa técnica é o projeto Clang : veja como os
.def
arquivos são usados lá. Com as macros,#include
é possível fornecer uma definição única, às vezes inteiramente declarativa, para uma coleção de coisas semelhantes que serão desenroladas em declarações de tipos,case
instruções sempre que apropriado, inicializadores padrão, etc. Aumenta significativamente a capacidade de manutenção: você nunca esquecerá de adicionar novoscase
instruções em todos os lugares quando você adicionou uma novaenum
, por exemplo.Portanto, como em qualquer outra ferramenta poderosa, você deve usar o pré-processador C com cuidado. Não existem regras genéricas na arte da programação, como "você nunca deve usar isso" ou "você sempre deve usar isso". Todas as regras nada mais são do que diretrizes.
fonte
Nunca é apropriado usar #defines assim. No seu caso, você pode fazer isso:
fonte
Não.
Para macros destinadas a serem usadas em código, uma boa diretriz para testar a adequação é cercar sua expansão entre parênteses (para expressões) ou chaves (para código) e ver se ainda será compilado:
As macros usadas nas declarações (como o exemplo na resposta de Andrew Shepherd) podem se livrar de um conjunto de regras mais frouxas, desde que não perturbem o contexto circundante (por exemplo, alternando entre
public
eprivate
).fonte
É uma coisa razoavelmente válida para se fazer em um programa "C" puro.
É desnecessário e confuso em um programa C ++.
Existem várias maneiras de evitar a digitação repetitiva de código em C ++. Ao usar os recursos fornecidos pelo seu IDE (mesmo com o vi, um simples "
%s/ pspace /<< " " <</g
" economizaria tanta digitação e ainda produziria código legível padrão). Você pode definir métodos particulares para implementar esse ou, para casos mais complexos, o modelo C ++ seria mais limpo e simples.fonte
Em C ++, isso pode ser resolvido com sobrecarga do operador. Ou mesmo algo tão simples quanto uma função variável:
lineWithSpaces(word1, word2, word3, ..., wordn)
é simples e economiza a digitaçãopSpaces
repetidamente.Portanto, embora no seu caso possa não parecer grande coisa, há uma solução mais simples e robusta.
Em geral, há poucos casos em que o uso de uma macro é significativamente mais curto sem a ofuscação e, principalmente, há uma solução suficientemente curta usando os recursos reais da linguagem (as macros são mais uma mera substituição de cadeia de caracteres).
fonte
Sim, é muito ruim. Eu já vi pessoas fazendo isso:
para salvar a digitação (o que você está tentando alcançar).
Esse código pertence apenas a lugares como este .
fonte
Macros são más e devem ser usadas somente quando você realmente precisa. Existem alguns casos em que as macros são aplicáveis (principalmente depuração). Mas em C ++, na maioria dos casos, você pode usar funções embutidas .
fonte
goto
, a todos os possíveis sistemas macro, etc. #Não, você não tem permissão para usar macros para salvar a digitação .
No entanto, você tem permissão, mesmo que seja necessário usá-los para separar parte não alterável do código das alterações e reduzir a redundância. Para o último, você deve pensar em alternativas e escolher macro somente se ferramentas melhores não funcionarem. (Para a prática, a macro está no final da linha, portanto, tê-la implica em último recurso ...)
Para reduzir a digitação, a maioria dos editores possui macros, até mesmo trechos de código inteligentes.
fonte
switch
/ etc, você pode apostar que vou usar macros para evitar enlouquecer - e aumentar a legibilidade. Usar macros para economizar digitação em palavras-chave, controlar o fluxo e coisas do gênero é estúpido - mas dizer que ninguém pode usá-las para salvar pressionamentos de tecla em contextos válidos é igualmente estúpido.