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 directive #ifdef
ou toute directive de préprocesseur imbriquée 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 bidouillage à 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 interested in
#define print_max(TYPE) \
if (TYPE##_MAX) \
printf("%lld\n", TYPE##_MAX);
print_max(INT);
print_max(BLAH);
Le préprocesseur Boost (qui fonctionne aussi bien pour C que pour 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 énuméré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 ce n’est pas vraiment 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 <values.h>
#include <stdio.h>
#include <boost/preprocessor.hpp>
/* 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 convertir 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 tricher - 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
Contrairement aux modèles, le préprocesseur n'est pas turing-complete . Un #ifdef
dans une macro n'est pas possible. Votre seule solution est de vous assurer que vous appelez uniquement print_max
sur les types pour lesquels un _MAX
correspondant est défini, par exemple. INT_MAX
. Le compilateur vous dira sûrement quand ils ne le seront pas.
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 <type>'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 <type> to determine how to calculate
* the minimum/maximum value.
*
* e.g., 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 (i.e., <type> 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))
Il n'y a pas de moyen facile de faire ça. 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
:
comme vous en avez besoin beaucoup (et qu'ils peuvent être utiles à plusieurs endroits), il est logique de les insérer 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);
Je ne pense pas que ce soit le cas de l'opérateur ## non 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.