Maison > développement back-end > C++ > le corps du texte

Comment pouvons-nous implémenter des macros récursives en C ?

Barbara Streisand
Libérer: 2024-11-17 19:49:02
original
133 Les gens l'ont consulté

How Can We Implement Recursive Macros in C?

Comprendre la récursion des macros pour les arguments de macro

En programmation C, les macros offrent un outil puissant pour la manipulation de texte. Un aspect intéressant est la possibilité d’utiliser des macros sur les arguments d’autres macros. Cependant, cela présente un défi technique, car les macros récursives ne sont généralement pas autorisées dans le langage.

Le problème : les macros récursives

Considérez le scénario dans lequel nous souhaitons créer une macro foreach, nommée PRINT_ALL, qui applique une macro donnée, PRINT, à une liste d'arguments. Par exemple :

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
Copier après la connexion

Cela invoquerait la macro PRINT sur chacune des variables a, b et d. L'approche naïve pourrait employer une macro récursive, comme suit :

#define FIRST_ARG(arg,...) arg
#define AFTER_FIRST_ARG(arg,...) , ##__VA_ARGS__
#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL PRINT(FIRST_ARG(__VA_ARGS__)); PRINT_ALL(AFTER_FIRST_ARG(__VA_ARGS__))
Copier après la connexion

Cependant, cette approche pose deux problèmes : les macros ne peuvent pas s'appeler de manière récursive, et il lui manque une condition d'arrêt pour arrêter la récursion.

Une solution de contournement récursive

Pour surmonter ces obstacles, une solution de contournement intelligente exploite une technique connue sous le nom de macro-évaluation-récursion. L'idée clé est d'émettre un texte de macro qui simule un appel de macro sans réellement invoquer la macro elle-même.

Considérez la macro suivante :

#define MAP_OUT
Copier après la connexion

Si nous avons les macros suivantes :

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
Copier après la connexion

L'évaluation de la macro A(blah) produit le texte de sortie :

blah B (blah)
Copier après la connexion

Ce texte sert de Espace réservé de remplacement de macro. Il peut être renvoyé au préprocesseur pour être étendu davantage, poursuivant ainsi le processus d'évaluation de la macro.

Pour faciliter cette récursivité, une série de macros EVAL sont définies :

#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL(...)EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
Copier après la connexion

Chaque macro s'applique plusieurs niveaux d'évaluation, amplifiant ainsi l'effet des macros appliquées.

Arrêter le Récursion

Pour contrôler la récursion, une macro spéciale, MAP_END, est définie :

#define MAP_END(...)
Copier après la connexion

L'évaluation de cette macro ne fait rien, mettant effectivement fin à la récursion.

Le prochain défi consiste à déterminer quand utiliser MAP_END au lieu de poursuivre la récursion. Pour y parvenir, une macro MAP_NEXT compare un élément de liste à un marqueur spécial de fin de liste. S'ils correspondent, il renvoie MAP_END ; sinon, il renvoie le paramètre suivant :

#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(item, next, ...) next MAP_OUT
#define MAP_NEXT1(item, next) MAP_NEXT0(item, next,0)
#define MAP_NEXT(item, next) MAP_NEXT1(MAP_GET_END item, next)
Copier après la connexion

En construisant soigneusement la macro MAP_NEXT, nous pouvons contrôler si la récursion continue ou se termine.

Implémentation finale

En combinant ces éléments de base, nous pouvons créer la macro MAP qui parcourt une liste et applique une macro donnée à chacune item :

#define MAP(f,...)EVAL(MAP1(f,__VA_ARGS__,(),0))
Copier après la connexion

Cette macro fonctionne en plaçant un marqueur de fin de liste à la fin de la liste, ainsi qu'un argument supplémentaire pour garantir la conformité ANSI. Il transmet ensuite la liste via plusieurs appels de macro EVAL et renvoie le résultat.

Cette technique fournit une solution créative au problème de l'utilisation de macros sur des arguments de macro. Il permet des capacités sophistiquées de manipulation de macros, permettant aux programmeurs d'étendre les fonctionnalités du préprocesseur de manière innovante.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal