Eu sei que eles são implementados extremamente inseguros em C / C ++. Eles não podem ser implementados de maneira mais segura? As desvantagens das macros são realmente ruins o suficiente para compensar o enorme poder que elas fornecem?
programming-languages
macros
Casebash
fonte
fonte
WithEvents
modificador do Visual Basic ? Você precisaria de algo como macros semânticas.Respostas:
Eu acho que a principal razão é que as macros são lexicais . Isso tem várias consequências:
O compilador não tem como verificar se uma macro está semanticamente fechada, ou seja, que representa uma "unidade de significado" como uma função. (Considere
#define TWO 1+1
- o que éTWO*TWO
igual? 3.)Macros não são digitadas como funções. O compilador não pode verificar se os parâmetros e o tipo de retorno fazem sentido. Ele só pode verificar a expressão expandida que usa a macro.
Se o código não compilar, o compilador não tem como saber se o erro está na própria macro ou no local em que a macro é usada. O compilador reportará o local errado na metade do tempo ou precisará reportar os dois, mesmo que um deles esteja provavelmente correto. (Considere
#define min(x,y) (((x)<(y))?(x):(y))
: O que o compilador deve fazer se os tipos dex
ey
não corresponderem ou não forem implementadosoperator<
?)As ferramentas automatizadas não podem trabalhar com elas de maneiras semanticamente úteis. Em particular, você não pode ter coisas como o IntelliSense para macros que funcionam como funções, mas se expandem para uma expressão. (Novamente, o
min
exemplo.)Os efeitos colaterais de uma macro não são tão explícitos quanto com as funções, causando confusão potencial para o programador. (Considere novamente o
min
exemplo: em uma chamada de função, você sabe que a expressão parax
é avaliada apenas uma vez, mas aqui você não pode saber sem olhar para a macro.)Como eu disse, essas são todas as consequências do fato de as macros serem lexicais. Quando você tenta transformá-los em algo mais adequado, você acaba com funções e constantes.
fonte
Mas sim, as macros podem ser projetadas e implementadas melhor do que em C / C ++.
O problema com as macros é que elas são efetivamente um mecanismo de extensão de sintaxe de linguagem que reescreve seu código em outra coisa.
No caso de C / C ++, não há verificação de sanidade fundamental. Se você for cuidadoso, tudo está bem. Se você cometer um erro, ou se usar demais macros, poderá encontrar grandes problemas.
Adicione a isso que muitas coisas simples que você pode fazer com macros (estilo C / C ++) podem ser feitas de outras maneiras em outros idiomas.
Em outros idiomas, como vários dialetos Lisp, as macros são mais bem integradas à sintaxe do idioma principal, mas você ainda pode ter problemas com as declarações em uma macro "vazando". Isso é tratado por macros higiênicas .
Breve contexto histórico
As macros (abreviação de instruções macro) apareceram pela primeira vez no contexto da linguagem assembly. Segundo a Wikipedia , as macros estavam disponíveis em alguns montadores da IBM na década de 1950.
O LISP original não tinha macros, mas foi introduzido pela primeira vez no MacLisp em meados da década de 1960: https://stackoverflow.com/questions/3065606/when-did-the-idea-of-macros-user-defined-code -transformation-aparecem .http://www.csee.umbc.edu/courses/331/resources/papers/Evolution-of-Lisp.pdf . Antes disso, "fexprs" fornecia funcionalidade semelhante a macro.
As versões mais antigas do C não tinham macros ( http://cm.bell-labs.com/cm/cs/who/dmr/chist.html ). Estes foram adicionados por volta de 1972-73 através de um pré-processador. Antes disso, C apenas suportava
#include
e#define
.O macro pré-processador M4 teve origem em 1977.
Linguagens mais recentes aparentemente implementam macros em que o modelo de operação é sintático e não textual.
Portanto, quando alguém fala sobre a primazia de uma definição específica do termo "macro", é importante observar que o significado evoluiu ao longo do tempo.
fonte
Macros podem, como Scott observa , permitir ocultar a lógica. Obviamente, o mesmo acontece com funções, classes, bibliotecas e muitos outros dispositivos comuns.
Mas um poderoso sistema de macros pode ir além, permitindo que você projete e utilize sintaxe e estruturas que normalmente não são encontradas no idioma. Essa pode ser uma ferramenta maravilhosa: idiomas específicos de domínio, geradores de código e muito mais, tudo dentro do conforto de um ambiente de idioma único ...
No entanto, pode ser abusado. Isso pode dificultar a leitura, a compreensão e a depuração do código, aumentar o tempo necessário para os novos programadores se familiarizarem com uma base de código e levar a erros e atrasos dispendiosos.
Portanto, para linguagens destinadas a simplificar a programação (como Java ou Python), esse sistema é um anátema.
fonte
As macros podem ser implementadas com muita segurança em algumas circunstâncias - no Lisp, por exemplo, macros são apenas funções que retornam código transformado como uma estrutura de dados (expressão s). Obviamente, o Lisp se beneficia significativamente do fato de ser homoicônico e do fato de que "código são dados".
Um exemplo de como as macros podem ser fáceis é este exemplo do Clojure que especifica um valor padrão a ser usado no caso de uma exceção:
Mesmo em Lisps, o conselho geral é "não use macros, a menos que você precise".
Se você não estiver usando uma linguagem homoicônica, as macros ficarão muito mais complicadas e as várias outras opções terão algumas armadilhas:
Além disso, tudo o que uma macro pode fazer pode ser conseguido de alguma outra maneira em uma linguagem completa (mesmo que isso signifique escrever muitos clichês). Como resultado de todo esse truque, não é de surpreender que muitas linguagens decidam que as macros não valem realmente todo o esforço para implementar.
fonte
Para responder às suas perguntas, pense sobre o uso predominante das macros (Aviso: código compilado pelo cérebro).
#define X 100
Isso pode ser facilmente substituído por:
const int X = 100;
#define max(X,Y) (X>Y?X:Y)
Em qualquer idioma que ofereça suporte à sobrecarga de funções, isso pode ser emulado de uma maneira muito mais segura, tendo funções sobrecarregadas do tipo correto ou, em um idioma que suporte genéricos, por uma função genérica. A macro tentará com prazer comparar qualquer coisa, incluindo ponteiros ou seqüências de caracteres, que podem ser compiladas, mas quase certamente não é o que você queria. Por outro lado, se você tornou as macros seguras para o tipo, elas não oferecem benefícios ou conveniência em relação às funções sobrecarregadas.
#define p printf
Isso é facilmente substituído por uma função
p()
que faz a mesma coisa. Isso está bastante envolvido em C (exigindo o uso dava_arg()
família de funções), mas em muitas outras linguagens que suportam números variáveis de argumentos de funções, é muito mais simples.O suporte a esses recursos em um idioma e não em um idioma macro especial é mais simples, menos propenso a erros e muito menos confuso para outras pessoas que leem o código. Na verdade, não consigo pensar em um único caso de uso para macros que não possam ser facilmente duplicadas de outra maneira. O único lugar em que as macros são realmente úteis é quando elas estão vinculadas a construções de compilação condicional como
#if
(etc.).Nesse ponto, não discutirei com você, pois acredito que soluções sem pré-processador para compilação condicional em linguagens populares são extremamente complicadas (como a injeção de bytecode em Java). Mas linguagens como D criaram soluções que não exigem um pré-processador e não são mais complicadas do que usar condicionais do pré-processador, além de serem muito menos propensas a erros.
fonte
In fact, I can't think of a single use-case for macros that can't easily be duplicated in another way
: em C, pelo menos, você não pode formar identificadores (nomes de variáveis) usando concatenação de token sem usar macros.enum
para definir as condições e uma matriz de cadeias constantes para definir as mensagens podem resultar em problemas se o enum e a matriz ficam fora de sincronia. Usar uma macro para definir todos os pares (enum, string) e incluir essa macro duas vezes com outras definições apropriadas no escopo a cada vez permite que cada um coloque cada valor de enum ao lado de sua string.O maior problema que já vi nas macros é que, quando muito usadas, elas tornam o código muito difícil de ler e manter, pois permitem ocultar a lógica na macro que pode ou não ser fácil de encontrar (e pode ou não ser trivial )
fonte
Antes de começar, observe que os MACROs em C / C ++ são muito limitados, propensos a erros e não são realmente úteis.
Os MACROs implementados na linguagem assembler LISP ou z / OS, por exemplo, podem ser confiáveis e incrivelmente úteis.
Mas, devido ao abuso da funcionalidade limitada em C, eles têm uma má reputação. Portanto, ninguém mais implementa macros; em vez disso, você obtém coisas como modelos, que fazem algumas das coisas simples que as macros costumavam fazer e coisas como anotações de Java, que fazem algumas das coisas mais complexas que as macro costumavam fazer.
fonte