Perché la libreria C utilizza macro e funzioni con lo stesso nome?


20

Sto leggendo "The Standard C Library" di PJ Plauger, il che è davvero interessante. Il libro spiega non solo come USARE la biblioteca ma anche come viene implementata.

Ho finito di leggere la ctype.hsezione e nell'intestazione le funzioni sono dichiarate sia come macro che come funzioni. Per esempio

int isdigit(int);

ma anche

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

Non capisco perché ENTRAMBI vengono utilizzati?

Inoltre, se provo a ricreare la mia ctypeintestazione e l'implementazione personalizzate, posso compilare correttamente solo se rimuovo la macro (commentando la definizione).

Questo aspetto non è stato veramente spiegato nel libro. Qualcuno può spiegare per favore?


Non c'è nulla nello standard C che costringe un compilatore a implementarlo come macro. La macro è molto probabilmente un residuo dei vecchi tempi in cui C non aveva allineamento. Sebbene un compilatore intelligente dovrebbe essere in grado di incorporare tale funzione, se necessario, senza una parola chiave incorporata esplicita. Quindi la macro simile a una funzione è presente solo perché il compilatore è stato implementato da qualcuno che non era brillante nel creare compilatori.

Risposte:


23

La macro è (putativamente) più efficiente, in quanto non comporta una chiamata di funzione. Può essere ottimizzato più facilmente, poiché comporta solo una ricerca dell'offset del puntatore.

La chiamata di funzione consente il collegamento con la stessa libreria anche se il programma è stato compilato senza la definizione di macro, se è stato compilato con un'intestazione diversa o semplicemente con una dichiarazione canaglia all'interno del file di origine. Ad esempio, se si dispone di un compilatore con la versione "migliorata" di ctype.h di qualcuno che non aveva la macro, la funzione esisterebbe comunque in fase di esecuzione per l'uso.

Se guardiamo allo standard:

7.1.4 Uso delle funzioni di libreria

Qualsiasi funzione dichiarata in un'intestazione può essere ulteriormente implementata come una macro simile a una funzione definita nell'intestazione, quindi se una funzione di libreria viene dichiarata in modo esplicito quando la sua intestazione è inclusa, una delle tecniche mostrate di seguito può essere utilizzata per garantire che la dichiarazione non sia influenzato da tale macro. Qualsiasi definizione macro di una funzione può essere soppressa localmente racchiudendo il nome della funzione tra parentesi, perché il nome non è seguito dalla parentesi sinistra che indica l'espansione di un nome di funzione macro. Per lo stesso motivo sintattico, è consentito prendere l'indirizzo di una funzione di libreria anche se è definita anche come macro.

Ciò significa che se scrivi:

int b = (isdigit)(c);

o

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

quindi stai invocando la funzione effettiva, non la macro. Puoi anche scrivere legalmente:

#undef isdigit
int b = isdigit(c);

oppure (in un file di origine che non ha #include <ctype.h>direttamente o transitivamente):

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

Come si può compilare il programma SENZA la definizione macro?
user619818

@ user619818 utilizzando extern int isdigit(int), ad esempio.
ecatmur

Proprio per questo sono chiaro, intendi che l'utente non ha #include <whatever> ma invece aggiunge int isdigit (int); nella parte superiore del file di implementazione. OK, leggi correttamente la tua risposta.
user619818

Avere una funzione richiamabile (rispetto al codice macro incorporato) consente anche ad altre lingue come Python e Perl di interfacciarsi con quelle funzioni
Technosaurus
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.