Est-il possible que les macros du préprocesseur C contiennent des directives de préprocesseur?

Je voudrais faire l’équivalent de ce qui suit:

#define print_max(TYPE) \ # ifdef TYPE##_MAX \ printf("%lld\n", TYPE##_MAX); \ # endif print_max(INT); 

Maintenant, la #ifdef ou toute directive de préprocesseur nestede n’est pas autorisée dans la mesure du possible dans une macro de fonction. Des idées?

Mise à jour: Il semble donc que ce ne soit pas possible. Même un hack à vérifier à l’exécution semble irréalisable. Donc, je pense que je vais aller avec quelque chose comme:

 #ifndef BLAH_MAX # define BLAH_MAX 0 #endif # etc... for each type I'm interestd in #define print_max(TYPE) \ if (TYPE##_MAX) \ printf("%lld\n", TYPE##_MAX); print_max(INT); print_max(BLAH); 

La bibliothèque Boost Preprocessor (qui fonctionne à la fois en C et en C ++, même si Boost dans son ensemble est une bibliothèque C ++) peut vous aider dans ce type de tâche. Au lieu d’utiliser un #ifdef dans une macro (ce qui n’est pas autorisé), cela vous aide à inclure un fichier plusieurs fois, avec différentes macros définies à chaque fois, de sorte que le fichier puisse utiliser #ifdef.

Le code suivant, s’il est enregistré dans max.c, doit faire ce que vous voulez pour chacun des mots répertoriés dans MAXES #define en haut du fichier. Toutefois, cela ne fonctionnera pas si l’une des valeurs _MAX est une virgule flottante, car le préprocesseur ne peut pas gérer les virgules flottantes.

(Boost Processor est un outil pratique, mais pas tout à fait simple; vous pouvez décider si cette approche constitue une amélioration par rapport au copier-coller.)

 #define MAXES (SHRT)(INT)(LONG)(PATH)(DOESNT_EXIST) #if !BOOST_PP_IS_ITERATING /* This portion of the file (from here to #else) is the "main" file */ #include  #include  #include  /* Define a function print_maxes that iterates over the bottom portion of this * file for each word in MAXES */ #define BOOST_PP_FILENAME_1 "max.c" #define BOOST_PP_ITERATION_LIMITS (0,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(MAXES))) void print_maxes(void) { #include BOOST_PP_ITERATE() } int main(int argc, char *argv[]) { print_maxes(); } #else /* This portion of the file is evaluated multiple times, with * BOOST_PP_ITERATION() resolving to a different number every time */ /* Use BOOST_PP_ITERATION() to look up the current word in MAXES */ #define CURRENT BOOST_PP_SEQ_ELEM(BOOST_PP_ITERATION(), MAXES) #define CURRENT_MAX BOOST_PP_CAT(CURRENT, _MAX) #if CURRENT_MAX printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is %lld\n", (long long) CURRENT_MAX); #else printf("The max of " BOOST_PP_STRINGIZE(CURRENT) " is undefined\n"); #endif #undef CURRENT #undef CURRENT_MAX #endif 

J’ai déjà essayé ça. Le problème est que # est déjà réservé pour ssortingnger un paramètre de macro. Il n’est pas analysé comme un jeton de préprocesseur comme celui de # define.

La seule solution que j’ai est de sortingcher – produire une liste de types qui ont un _XXX_MAX comme un ensemble de définit, puis utilisez-le. Je ne sais pas comment produire la liste de manière automatisée en pré-processeur, donc je n’essaie pas. L’hypothèse est que la liste n’est pas trop longue et ne sera pas maintenue de manière trop intensive.

 #define PRINT_MAX(type) printf("%lld\n", _TYPE##_MAX); #define HAVE_MAX(type) _TYPE##_MAX // not sure if this works /* a repetitious block of code that I cannot factor out - this is the cheat */ #ifdef HAVE_MAX(INT) #define PRINT_INT_MAX PRINT_MAX(INT) #endif #ifdef HAVE_MAX(LONG) #define PRINT_LONG_MAX PRINT_MAX(LONG) #endif /* end of cheat */ #define print_max(type) PRINT_##TYPE##_MAX 

Je ne pense pas que l’opérateur ## ne soit pas autorisé dans un #ifdef. J’ai essayé ceci:

 #define _print_max(TYPE) \ #ifdef TYPE \ printf("%lld\n", _TYPE); \ #endif #define print_max(TYPE) _print_max(MAX##_TYPE) void main() { print_max(INT) } 

et cela ne fonctionnait toujours pas (il n’aimait pas #ifdef TYPE). Le problème est que #ifdef n’acceptera que des symboles # définis, pas des arguments #define. Ce sont deux choses différentes.

Contrairement aux modèles, le préprocesseur n’est pas complet . Un #ifdef dans une macro n’est pas possible. Votre seule solution consiste à appeler uniquement print_max sur les types pour lesquels un _MAX correspondant _MAX défini, par exemple INT_MAX . Le compilateur vous dira sûrement quand ils ne le seront pas.

Il n’y a pas de moyen facile de faire cela. Le plus proche possible est de # définir un grand nombre de macros IFDEF telles que:

 #undef IFDEF_INT_MAX #ifdef INT_MAX #define IFDEF_INT_MAX(X) X #else #define IFDEF_INT_MAX(X) #endif #undef IFDEF_BLAH_MAX #ifdef BLAH_MAX #define IFDEF_BLAH_MAX(X) X #else #define IFDEF_BLAH_MAX(X) #endif : 

Puisque vous en avez besoin beaucoup (et qu’ils peuvent être utiles à plusieurs endroits), il est logique de les coller dans leur propre fichier d’en-tête ‘ifdefs.h’ que vous pouvez inclure à tout moment. Vous pouvez même écrire un script qui régénère ifdef.h à partir d’une liste de ‘macros d’intérêt’

Ensuite, votre code devient

 #include "ifdefs.h" #define print_max(TYPE) \ IFDEF_##TYPE##_MAX( printf("%lld\n", TYPE##_MAX); ) print_max(INT); print_max(BLAH); 

Tant que vous ne vous intéressez qu’aux valeurs intégrales, et en supposant que le matériel utilise des octets complémentaires de 2 et des octets de 8 bits:

 // Of course all this MAX/MIN stuff assumes 2's compilment, with 8-bit bytes... #define LARGEST_INTEGRAL_TYPE long long /* This will evaluate to TRUE for an unsigned type, and FALSE for a signed * type. We use 'signed char' since it should be the smallest signed type * (which will sign-extend up to 's size) vs. possibly overflowing if * going in the other direction (from a larger type to a smaller one). */ #define ISUNSIGNED(type) (((type) ((signed char) -1)) > (type) 0) /* We must test for the "signed-ness" of  to determine how to calculate * the minimum/maximum value. * * eg, If a typedef'ed type name is passed in that is actually an unsigned * type: * * typedef unsigned int Oid; * MAXIMUM_(Oid); */ #define MINIMUM_(type) ((type) (ISUNSIGNED(type) ? MINIMUM_UNSIGNED_(type) \ : MINIMUM_SIGNED_( type))) #define MAXIMUM_(type) ((type) (ISUNSIGNED(type) ? MAXIMUM_UNSIGNED_(type) \ : MAXIMUM_SIGNED_( type))) /* Minumum unsigned value; zero, by definition -- we really only have this * macro for symmetry. */ #define MINIMUM_UNSIGNED_(type) ((type) 0) // Maximum unsigned value; all 1's. #define MAXIMUM_UNSIGNED_(type) \ ((~((unsigned LARGEST_INTEGRAL_TYPE) 0)) \ >> ((sizeof(LARGEST_INTEGRAL_TYPE) - sizeof(type)) * 8)) /* Minimum signed value; a 1 in the most-significant bit. * * We use LARGEST_INTEGRAL_TYPE as our base type for the initial bit-shift * because we should never overflow (ie,  should always be the same * size or smaller than LARGEST_INTEGRAL_TYPE). */ #define MINIMUM_SIGNED_(type) \ ((type) \ ((signed LARGEST_INTEGRAL_TYPE) \ (~((unsigned LARGEST_INTEGRAL_TYPE) 0x0) << ((sizeof(type) * 8) - 1)))) // Maximum signed value; 0 in most-significant bit; remaining bits all 1's. #define MAXIMUM_SIGNED_(type) (~MINIMUM_SIGNED_(type))