Is it possible for C preprocessor macros to contain preprocessor directives?

后端 未结 7 1284
醉话见心
醉话见心 2020-12-08 19:33

I would like to do the equivalent of the following:

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

prin         


        
相关标签:
7条回答
  • 2020-12-08 20:09

    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
    
    0 讨论(0)
  • 2020-12-08 20:10

    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.

    0 讨论(0)
  • 2020-12-08 20:11

    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.

    0 讨论(0)
  • 2020-12-08 20:19

    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);
    
    0 讨论(0)
  • 2020-12-08 20:25

    The Boost Preprocessor (which works for C as well as C++, even though Boost as a whole is a C++ library) library can help with this kind of task. Instead of using an #ifdef within a macro (which isn't permitted), it helps you include a file multiple times, with different macros defined each time, so that the file can use #ifdef.

    The following code, if saved to max.c, should do what you want for each of the words listed in the MAXES #define at the top of the file. However, it won't work if any of the _MAX values are floating point, since the preprocessor can't handle floating point.

    (Boost Processor is a handy tool, but it's not exactly straightforward; you can decide whether or not this approach is an improvement over copy-and-paste.)

    #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
    
    0 讨论(0)
  • 2020-12-08 20:26

    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.

    0 讨论(0)
提交回复
热议问题