Pergunta

Em uma pergunta o que eu pensava que era uma boa resposta foi rejeitada para o uso sugerido de macros

#define radian2degree(a) (a * 57.295779513082)
#define degree2radian(a) (a * 0.017453292519)

em vez de funções inline. Por favor, desculpe a pergunta novato, mas o que é tão mal sobre macros neste caso?

Foi útil?

Solução

Há um par de coisas estritamente más sobre macros.

Eles são processamento de texto, e não são escopo. Se você #define foo 1, então qualquer posterior utilização foo como um identificador irá falhar. Isso pode levar a erros de compilação ímpares e erros de tempo de execução de encontrar duros.

Eles não levam argumentos no sentido normal. Você pode escrever uma função que vai levar dois valores int e retornar o máximo, porque os argumentos serão avaliados uma vez e os valores utilizados posteriormente. Você não pode escrever uma macro para fazer isso, porque vai avaliar pelo menos um argumento duas vezes, e falhar com algo como max(x++, --y).

Há também armadilhas comuns. É difícil obter várias declarações direito neles, e eles exigem um monte de parênteses possivelmente supérfluas.

No seu caso, você precisa de parênteses:

#define radian2degree(a) (a * 57.295779513082)

precisa ser

#define radian2degree(a) ((a) * 57.295779513082)

e você ainda está pisando em alguém que escreve uma função radian2degree em algum espaço interior, confiante de que essa definição vai trabalhar em seu próprio âmbito.

Outras dicas

A maioria das outras respostas discutir por macros são maus incluindo a forma como o seu exemplo tem um uso macro falha comum. Está aqui a tomada de Stroustrup: http://www.research.att.com/~bs /bs_faq2.html#macro

Mas a sua pergunta estava perguntando o que macros ainda são bons para. Há algumas coisas onde as macros são melhores do que funções inline, e é aí que você está fazendo coisas que simplesmente não pode ser feito com funções embutidas, tais como:

  • símbolo colar
  • lidar com números de linha ou tal (como para a criação de mensagens de erro no assert())
  • lidar com coisas que não são expressões (por exemplo, como muitas implementações de uso offsetof() usando um nome de tipo para criar uma operação de elenco)
  • a macro para obter uma contagem de elementos da matriz (não pode fazê-lo com uma função, como os decaimentos nome da matriz para um ponteiro com muita facilidade)
  • função semelhante a criação de 'tipo polimórfico' coisas em C, onde modelos não estão disponíveis

Mas com uma linguagem que tem em linha funções, os usos mais comuns de macros não deve ser necessário. Eu sou mesmo relutantes em usar macros quando estou lidando com um compilador C que não suporta funções inline. E eu não tentar usá-los para criar funções do tipo agnóstico, se possível (criando várias funções com um indicador de tipo como parte do nome do lugar).

Eu também mudou-se para usar enums para constantes numéricas nomeados em vez de #define.

Para esta macro específica, se eu usá-lo da seguinte forma:

int x=1;
x = radian2degree(x);
float y=1;
y = radian2degree(y);

não haveria nenhuma verificação de tipo, e x, y conterá valores diferentes.

Além disso, o código a seguir

float x=1, y=2;
float z = radian2degree(x+y);

não vai fazer o que você pensa, uma vez que irá traduzir para

float z = x+y*0.017453292519;

em vez de

float z = (x+y)+0.017453292519;

que é o resultado esperado.

Estes são apenas alguns exemplos para o mau comportamento ans uso indevido macros possa ter.

Editar

Você pode ver adicionais discussões sobre este aqui

As macros são relativamente freqüentemente abusada e pode-se facilmente cometer erros usando-os como demonstrado pelo seu exemplo. Leve o radian2degree expressão (1 + 1):

  • com a macro se expandirá para 1 + 1 * 57,29 ... = 58,29 ...
  • com uma função que vai ser o que você quer que seja, a saber (1 + 1) * 57,29 ... = ...

De modo mais geral, as macros são maus porque eles olhar como funções para que induzi-lo a usá-los apenas como funções mas eles têm regras sutis de seu próprio . Neste caso, a maneira correta seria escrever seria (aviso o parêntese em torno de um):

#define radian2degree(a) ((a) * 57.295779513082)

Mas você deve manter em linha funções. Veja estas ligações a partir do C ++ FAQ Lite para mais exemplos de macros do mal e suas sutilezas:

Se possível, use sempre função inline. Estes são typesafe e não pode ser facilmente redefinida.

define podem ser redfined indefinido, e não há nenhuma verificação de tipo.

pré-processador do compilador é uma coisa finnicky, e, portanto, um candidato terrível para truques inteligentes. Como outros têm para fora pontas, é fácil para o compilador para entender mal sua intenção com a macro, e é fácil para você não entender o que a macro vai realmente fazer, mas o mais importante, você não pode entrar em macros no depurador

Macros são maus, porque você pode acabar passando mais de uma variável ou um escalar a ele e isso pode resolver em um comportamento indesejado (definir uma macro máximo para determinar máximo entre um e b, mas passar um ++ e b ++ para a macro e ver o que acontece).

Se a sua função vai ser embutido de qualquer maneira, não há nenhuma diferença de desempenho entre uma função e uma macro. No entanto, existem várias diferenças de usabilidade entre uma função e uma macro, os quais defendem o uso de uma função.

Se você construir a macro corretamente, não há nenhum problema. Mas se você usar uma função, o compilador irá fazê-lo corretamente para você o tempo todo. Então, usando uma função faz com que seja mais difícil de escrever código ruim.

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