Pourquoi la bibliothèque C utilise-t-elle des macros et des fonctions du même nom?

20

Je lis «The Standard C Library» de PJ Plauger, ce qui est vraiment intéressant. Le livre explique non seulement comment UTILISER la bibliothèque mais aussi comment elle est implémentée.

J'ai fini de lire la ctype.hsection et dans l'en-tête les fonctions sont déclarées à la fois comme macros ET fonctions. Par exemple

int isdigit(int);

mais aussi

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

Je ne comprends pas pourquoi les DEUX sont utilisés?

De plus, si j'essaie de recréer mon propre en- ctypetête et implémentation personnalisés, je ne peux compiler avec succès que si je supprime la macro (commentez la définition).

Cet aspect n'était pas vraiment expliqué dans le livre. Quelqu'un peut-il expliquer?

user619818
la source
Rien dans la norme C n'oblige un compilateur à l'implémenter en tant que macro. La macro est probablement un résidu de l'ancien temps où C n'avait pas d'incrustation. Bien qu'un compilateur intelligent devrait être en mesure d'inline cette fonction si nécessaire, sans mot clé inline explicite. Donc, la macro de type fonction n'est là que parce que le compilateur a été implémenté par quelqu'un qui n'était pas brillant pour faire des compilateurs.

Réponses:

23

La macro est (putativement) plus efficace, car elle n'implique pas d'appel de fonction. Il peut être optimisé plus facilement, car il implique simplement une recherche de décalage de pointeur.

L'appel de fonction permet de créer des liens avec la même bibliothèque même si le programme a été compilé sans la définition de macro - s'il a été compilé avec un en-tête différent, ou simplement avec une déclaration non autorisée à l'intérieur du fichier source. Si, par exemple, vous avez un compilateur qui a la version "améliorée" de quelqu'un de ctype.h qui n'avait pas la macro, la fonction existerait toujours au moment de l'exécution pour être utilisée.

Si nous regardons la norme:

7.1.4 Utilisation des fonctions de bibliothèque

Toute fonction déclarée dans un en-tête peut en outre être implémentée en tant que macro de type fonction définie dans l'en-tête, donc si une fonction de bibliothèque est déclarée explicitement lorsque son en-tête est inclus, l'une des techniques indiquées ci-dessous peut être utilisée pour garantir que la déclaration n'est pas affecté par une telle macro. Toute définition de macro d'une fonction peut être supprimée localement en plaçant le nom de la fonction entre parenthèses, car le nom n'est pas suivi de la parenthèse gauche qui indique l'expansion d'un nom de macro fonction. Pour la même raison syntaxique, il est permis de prendre l'adresse d'une fonction de bibliothèque même si elle est également définie comme macro.

Cela signifie que si vous écrivez:

int b = (isdigit)(c);

ou

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

alors vous appelez la fonction réelle, pas la macro. Vous pouvez également légalement écrire:

#undef isdigit
int b = isdigit(c);

ou (dans un fichier source n'ayant pas #include <ctype.h>directement ou transitivement):

extern int isdigit(int);
int b = isdigit(c);
ecatmur
la source
Comment le programme pourrait-il être compilé SANS la définition de macro?
user619818
@ user619818 en utilisant extern int isdigit(int), par exemple.
ecatmur
Juste pour que je sois clair, vous voulez dire que l'utilisateur n'a pas de #include <quoique ce soit> mais ajoute à la place int isdigit (int); en haut du fichier d'implémentation. OK, lisez correctement votre réponse.
user619818
Avoir une fonction appelable (par rapport au code macro intégré) permet également à d'autres langages comme python et perl de s'interfacer avec ces fonctions
technosaurus