Is it possible for C preprocessor macros to contai

2019-01-17 14:56发布

I would like to do the equivalent of the following:

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

print_max(INT);

Now the #ifdef or any nested preprocessor directive is not allowed as far as I can see in a function macro. Any ideas?

Update: So it seems like this is not possible. Even a hack to check at runtime seems unachievable. So I think I'll go with something like:

#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);

7条回答
smile是对你的礼貌
2楼-- · 2019-01-17 15:18

Unlike templates, the preprocessor is not turing-complete. An #ifdef inside a macro is not possible. Your only solution is to make sure you only call print_max on types which has a matching _MAX defined, e.g. INT_MAX. The compiler will surely tell you when they aren't.

查看更多
甜甜的少女心
3楼-- · 2019-01-17 15:20

The only solution I have is cheating - produce a list of types that have an _XXX_MAX as a set of defines, and then use that. I don't know how to produce the list in automated fashion in preprocessor, so I don't try. The assumption is that the list is not too long and will not be maintained too intensively.

#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
查看更多
Rolldiameter
4楼-- · 2019-01-17 15:21

There's no easy way to do this. The closest you can come is to #define a large number of IFDEF macros such as:

#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

     :

since you need a lot of them (and they might be useful multiple places), it makes a lot of sense to stick all these in their own header file 'ifdefs.h' which you can include whenever you need them. You can even write a script that regenerates ifdef.h from a list of 'macros of interest'

Then, your code becomes

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

print_max(INT);
print_max(BLAH);
查看更多
Animai°情兽
5楼-- · 2019-01-17 15:34

As long as you're only interested in integral values, and assuming hardware using 2's compliment and 8-bit bytes:

// 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))
查看更多
太酷不给撩
6楼-- · 2019-01-17 15:36

I've tried that before. The problem is that # is already reserved to stringize a macro parameter. It isn't parsed as a preprocessor token like the one in #define.

查看更多
聊天终结者
7楼-- · 2019-01-17 15:36

I don't think it's a case of the ## operator not being allowed in an #ifdef. I tried this:

#define _print_max(TYPE) \
#ifdef TYPE \
printf("%lld\n", _TYPE); \
#endif

#define print_max(TYPE) _print_max(MAX##_TYPE)


void main() 
{
    print_max(INT)
}

and it still didn't work (it didn't like #ifdef TYPE). The problem is that #ifdef will only accept #defined symbols, not #define arguments. Those are two different things.

查看更多
登录 后发表回答