Eu não entendo bem o conceito macro. O que é uma macro? Eu não entendo como é diferente da função? Tanto a função quanto a macro contêm um bloco de código. Então, como a macro e a função diferem?
programming-practices
Edoardo Sorgentone
fonte
fonte
Respostas:
Nota
Gostaria de acrescentar o seguinte esclarecimento após observar o padrão de votação de polarização nesta resposta.
A resposta não foi escrita tendo em mente a precisão técnica e a ampla generalização. Foi uma tentativa humilde de explicar em linguagem simples, a diferença entre macros e funções para um iniciante em programação, sem tentar ser completo ou preciso (na verdade, está longe de ser preciso). A linguagem de programação C estava em minha mente ao redigir a resposta, mas minhas desculpas por não mencioná-la claramente e causar qualquer confusão (potencial).
Realmente considero a resposta compartilhada por Jörg W Mittag . Foi uma leitura perspicaz (quanto menos eu sei) e votei novamente logo após a publicação. Acabei de começar no Software Engineering Stack Exchange, e a experiência e as discussões até agora foram realmente esclarecedoras.
Deixarei essa resposta aqui, pois ela pode ser útil para outros iniciantes em desenvolvimento de software, tentando entender um conceito sem ficar atolado em precisões técnicas.
Tanto a macro quanto a função representam a unidade de código independente. Ambos são ferramentas que auxiliam no design modular de um programa. Do ponto de vista do programador que está escrevendo o código fonte, eles parecem bastante semelhantes. No entanto, eles diferem na maneira como são tratados durante o ciclo de vida de execução do programa.
Uma macro é definida uma vez e usada em vários locais de um programa. A macro é expandida em linha durante o estágio de pré-processamento. Portanto, tecnicamente, não permanece uma entidade separada depois que o código-fonte é compilado. As instruções na definição de macro tornam-se parte das instruções do programa, assim como outras instruções.
O motivo por trás da gravação de uma macro é facilitar a escrita e o gerenciamento do código-fonte para o programador. Geralmente, as macros são desejadas para tarefas mais simples, nas quais escrever uma função completa seria uma penalidade de sobrecarga de desempenho / tempo de execução. Exemplos de situações em que uma macro é preferível à função são:
Usando valores constantes (como valores matemáticos ou científicos) ou algum parâmetro específico do programa.
Imprimir mensagens de log ou manipular asserções.
Executando cálculos simples ou verificações de condição.
Ao usar a macro, é fácil fazer alterações / correções em um local que estão instantaneamente disponíveis em qualquer lugar em que a macro é usada no programa. É necessária uma recompilação simples do programa para que as alterações tenham efeito.
O código de função, por outro lado, é compilado como uma unidade separada dentro do programa e é carregado na memória durante a execução do programa somente se necessário. O código de função mantém sua identidade independente do restante do programa. O código carregado é reutilizado se a função for chamada mais de uma vez. Quando a chamada de função é encontrada no programa em execução, o controle é passado a ele pelo subsistema de tempo de execução e o contexto do programa em execução (endereço da instrução de retorno) é preservado.
No entanto, há uma pequena penalidade no desempenho que precisa ser encontrada ao chamar uma função (alternância de contexto, preservação do endereço de retorno das principais instruções do programa, passagem de parâmetros e manipulação de valores de retorno etc.). Portanto, o uso da função é desejado apenas para blocos complexos de código (contra macros que manipulam casos mais simples).
Com a experiência, um programador toma uma decisão criteriosa como se um pedaço de código seria um bom ajuste como macro ou função na arquitetura geral do programa.
fonte
Infelizmente, existem vários usos diferentes do termo "macro" na programação.
Na família de idiomas Lisp e idiomas inspirados por eles, assim como em muitas linguagens funcionais ou inspiradas em funções modernas como Scala e Haskell, além de algumas linguagens imperativas como Boo, uma macro é um pedaço de código que é executado em tempo de compilação (ou pelo menos antes do tempo de execução para implementações sem um compilador) e pode transformar a Árvore de Sintaxe Abstrata (ou qualquer que seja o equivalente na linguagem específica, por exemplo, no Lisp, seriam as Expressões-S) em outra coisa durante a compilação. Por exemplo, em muitas implementações de esquema,
for
é uma macro que se expande em várias chamadas para o corpo. Nas linguagens de tipo estático, as macros geralmente são seguras, ou seja, não podem produzir código que não seja bem-digitado.Na família de idiomas C, as macros são mais como substituição de texto. O que também significa que eles podem produzir código que não é bem digitado ou que não é sintaticamente legal.
Nos montadores de macros, "macros" se referem a "instruções virtuais", isto é, instruções que a CPU não suporta nativamente, mas que são úteis; portanto, o montador permite que você use essas instruções e as expande em várias instruções que a CPU entende. .
No script de aplicativo, uma "macro" refere-se a uma série de ações que o usuário pode "gravar" e "reproduzir".
Todos esses são, em certo sentido, tipos de código executável, o que significa que, em certo sentido, podem ser vistos como funções. No entanto, no caso das macros Lisp, por exemplo, suas entradas e saídas são fragmentos de programa. No caso de C, suas entradas e saídas são tokens. Os três primeiros também têm a distinção muito importante de que eles são executados em tempo de compilação . De fato, as macros do pré-processador C, como o nome indica, são realmente executadas antes que o código chegue ao compilador .
fonte
Na família da linguagem C, uma definição de macro , um comando de pré-processador, especifica um modelo de código parametrizado que é substituído na chamada de macro sem ser compilado na definição. Isso significa que todas as variáveis livres devem ser vinculadas no contexto da chamada de macro. Argumentos de parâmetro com um efeito colateral semelhante
i++
poderiam ser repetidos pelo uso plural do parâmetro. A substituição textual do argumento1 + 2
de algum parâmetrox
ocorre antes da compilação e pode causar comportamento inesperadox * 3
(7
io9
). Um erro no corpo da macro da definição de macro será exibido apenas na compilação na chamada de macro.A definição da função especifica código com variáveis livres vinculadas ao contexto do corpo da função; não é a chamada de função .
No entanto, a macro aparentemente negativa fornece acesso à chamada, ao número da linha e ao arquivo de origem, ao argumento como string .
fonte
Em termos um pouco mais abstratos, uma macro é a sintaxe, como uma função é os dados. Uma função (no resumo) encapsula alguma transformação nos dados. Ele pega seus argumentos como dados avaliados, realiza algumas operações neles e retorna um resultado que também é apenas dados.
Uma macro, por outro lado, utiliza uma sintaxe não avaliada e opera com base nisso. Para idiomas do tipo C, a sintaxe entra no nível do token. Para idiomas com macros do tipo LISP, eles obtêm a sintaxe representada como um AST. A macro deve retornar um novo pedaço de sintaxe.
fonte
Uma macro geralmente se refere a algo expandido , substituindo a "chamada" da macro durante a compilação ou pré-processamento por instruções individuais no idioma de destino. Em tempo de execução, geralmente não há indicação de onde a macro começa e termina.
Isso é diferente de uma sub - rotina , que é um pedaço de código reutilizável, localizado separadamente na memória, para o qual o controle é passado no tempo de execução . As "funções", "procedimentos" e "métodos" na maioria das linguagens de programação se enquadram nessa categoria.
Como a resposta de Jörg W Mittag discute, os detalhes exatos variam entre os idiomas: em alguns, como C, uma macro executa substituição de texto no código-fonte; em alguns, como o Lisp, ele executa a manipulação de uma forma intermediária como uma Árvore de Sintaxe Abstrata. Existem também algumas áreas cinzentas: algumas linguagens têm notação para "funções embutidas", definidas como uma função, mas expandidas no programa compilado como uma macro.
A maioria dos idiomas incentiva os programadores a raciocinar sobre cada sub-rotina isoladamente, definindo contratos de tipo para entradas e saídas e ocultando outras informações sobre o código de chamada. Geralmente, há um impacto no desempenho ao chamar uma sub-rotina na qual as macros não incorrem e as macros podem ser capazes de manipular o programa de maneiras que uma sub-rotina não pode. Portanto, as macros podem ser consideradas "nível inferior" que as sub-rotinas, porque operam em uma base menos abstrata.
fonte
A macro é executada durante a compilação e a função é executada em tempo de execução.
Exemplo:
Portanto, durante a compilação, o código é realmente alterado para:
fonte