Maison > développement back-end > C++ > Comment pouvez-vous obtenir une fonctionnalité de macro récursive en C, malgré les limites de l'expansion des macros ?

Comment pouvez-vous obtenir une fonctionnalité de macro récursive en C, malgré les limites de l'expansion des macros ?

Barbara Streisand
Libérer: 2024-11-16 02:17:03
original
329 Les gens l'ont consulté

How can you achieve recursive macro functionality in C, despite the limitations of macro expansion?

Macros récursives en C à l'aide de macros d'arguments

En programmation C, il n'est pas simple d'appliquer des macros de manière récursive aux arguments de macro. Cependant, en utilisant une solution de contournement complexe, il est possible d'obtenir une macro MAP avec la fonctionnalité souhaitée.

Principes fondamentaux

Pour lancer la récursivité, nous définissons une macro MAP_OUT qui sert d'espace réservé pour extension de macro :

#define MAP_OUT
Copier après la connexion

Ensuite, nous créons deux macros, A et B, pour démontrer récursion :

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

L'évaluation de A(blah) donne le résultat suivant :

blah B (blah)
Copier après la connexion

Le préprocesseur traite B(blah) comme du texte brut puisqu'il ne s'agit pas encore d'un appel de macro. Lorsque ce texte est retraité, il se développe pour produire :

blah blah A (blah)
Copier après la connexion

En réinjectant continuellement la sortie dans le préprocesseur, nous pouvons maintenir la récursion indéfiniment.

Évaluation récursive

Pour automatiser cette évaluation répétée, nous utilisons la macro EVAL :

#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

La macro EVAL propage ses arguments à travers une arborescence d'appels de macro, multipliant leur nombre d'évaluations par 365.

Terminaison de récursion

Pour éviter une récursion sans fin, nous avons besoin d'un mécanisme de terminaison. Nous définissons une macro spéciale nommée MAP_END :

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

Lorsqu'elle est évaluée, cette macro ne fait rien, arrêtant effectivement la récursivité.

Pour choisir entre les macros récursives et de fin, nous introduisons MAP_NEXT :

#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

MAP_NEXT compare l'élément actuel avec le marqueur de fin de liste (). Il renvoie MAP_END s'ils correspondent, ou le paramètre suivant dans le cas contraire.

Mise en œuvre pratique

En combinant ces éléments, nous pouvons créer des versions pratiques des macros A et B :

#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
Copier après la connexion

MAP0 et MAP1 appliquent l'opération f à l'élément actuel x. Ils vérifient ensuite l'élément suivant, peek, pour déterminer s'il faut continuer ou mettre fin à la récursion.

Enfin, nous lions le tout avec la macro MAP de niveau supérieur :

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

Lieux MAP un marqueur de fin de liste sur la liste d'arguments et le transmet via EVAL.

En utilisant ces techniques, vous pouvez obtenir une fonctionnalité de macro récursive en C, permettant des traitement basé sur des macros.

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