Por que a biblioteca C usa macros e funções com o mesmo nome?


20

Estou lendo 'The Standard C Library' de PJ Plauger, o que é realmente interessante. O livro explica não apenas como USAR a biblioteca, mas também como ela é implementada.

Eu terminei de ler a ctype.hseção e no cabeçalho as funções são declaradas como macros AND. Por exemplo

int isdigit(int);

mas também

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

Eu não entendo por que AMBOS são usados?

Além disso, se eu tentar recriar meu próprio ctypecabeçalho e implementação personalizados , só posso compilar com êxito se remover a macro (comente a definição).

Este aspecto não foi realmente explicado no livro. Alguém pode me explicar?


Não há nada no padrão C forçando um compilador a implementá-lo como uma macro. A macro provavelmente é um resíduo dos velhos tempos em que C não tinha embutido. Embora um compilador inteligente possa ser capaz de incorporar essa função, se necessário, sem uma palavra-chave embutida explícita. Portanto, a macro de função está presente apenas porque o compilador foi implementado por alguém que não era brilhante em criar compiladores.

Respostas:


23

A macro é (putativamente) mais eficiente, pois não envolve uma chamada de função. Ele pode ser otimizado mais facilmente, pois envolve apenas uma pesquisa de deslocamento do ponteiro.

A chamada de função permite vincular a mesma biblioteca, mesmo que o programa tenha sido compilado sem a definição de macro - se ele foi compilado com um cabeçalho diferente ou apenas com uma declaração não autorizada dentro do arquivo de origem. Por exemplo, se você tiver um compilador com a versão "aprimorada" de ctype.h de alguém que não possui a macro, a função ainda existiria no tempo de execução para uso.

Se olharmos para o padrão:

7.1.4 Uso de funções da biblioteca

Qualquer função declarada em um cabeçalho pode ser implementada adicionalmente como uma macro de função definida no cabeçalho, portanto, se uma função de biblioteca for declarada explicitamente quando seu cabeçalho for incluído, uma das técnicas mostradas abaixo pode ser usada para garantir que a declaração não seja afetado por essa macro. Qualquer definição de macro de uma função pode ser suprimida localmente, colocando o nome da função entre parênteses, porque o nome não é seguido pelo parêntese esquerdo que indica a expansão de um nome de função de macro. Pela mesma razão sintática, é permitido usar o endereço de uma função de biblioteca, mesmo que ela também seja definida como uma macro.

Isso significa que se você escrever:

int b = (isdigit)(c);

ou

int (*f)(int) = &isdigit;
int b = f(c);

então você está invocando a função real, não a macro. Você também pode escrever legalmente:

#undef isdigit
int b = isdigit(c);

ou (em um arquivo de origem que não tenha #include <ctype.h>direta ou transitivamente):

extern int isdigit(int);
int b = isdigit(c);

Como o programa pode ser compilado SEM a definição de macro?
User619818

@ user619818 usando extern int isdigit(int), por exemplo.
Ecatmur

Só para esclarecer, você quer dizer que o usuário não tem #include <whatever>, mas adiciona int isdigit (int); no topo do arquivo de implementação. OK, basta ler sua resposta corretamente.
user619818

Ter uma função que pode ser chamado (vs. inline código de macro) também permite que outras linguagens como Python e Perl para a interface com essas funções
Technosaurus
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.