【问题标题】:Is it possible for C preprocessor macros to contain preprocessor directives?C 预处理器宏是否可以包含预处理器指令?
【发布时间】:2010-09-23 00:52:14
【问题描述】:

我想做相当于以下的事情:

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

print_max(INT);

现在#ifdef 或任何嵌套的预处理器指令是 据我在函数宏中看到的,不允许。 有什么想法吗?

更新:所以这似乎是不可能的。即使是在运行时检查的 hack 似乎也无法实现。所以我想我会选择类似的东西:

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

【问题讨论】:

    标签: c macros nested c-preprocessor expansion


    【解决方案1】:

    我认为这不是#ifdef 中不允许使用## 运算符的情况。我试过这个:

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

    它仍然没有工作(它不喜欢#ifdef TYPE)。问题是#ifdef 将只接受#defined 符号,而不接受#define 参数。这是两个不同的东西。

    【讨论】:

      【解决方案2】:

      我以前试过。问题是# 已被保留用于对宏参数进行字符串化。它不会像#define 中那样被解析为预处理器令牌。

      【讨论】:

      • 非常直接的答案解释了为什么这根本不可能。
      【解决方案3】:

      与模板不同,预处理器不是turing-complete。不能在宏内使用#ifdef。您唯一的解决方案是确保仅在定义了匹配的_MAX 的类型上调用print_max,例如INT_MAX。当它们不是时,编译器肯定会告诉你。

      【讨论】:

        【解决方案4】:

        我唯一的解决方案是作弊 - 生成一个类型列表,其中包含 _XXX_MAX 作为一组定义,然后使用它。我不知道如何在预处理器中以自动化方式生成列表,所以我不尝试。假设列表不会太长,也不会维护得太密集。

        #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
        

        【讨论】:

          【解决方案5】:

          Boost Preprocessor(它适用于 C 和 C++,尽管 Boost 作为一个整体是一个 C++ 库)库可以帮助完成此类任务。它不是在宏中使用#ifdef(这是不允许的),而是帮助您多次包含一个文件,每次定义不同的宏,以便文件可以使用#ifdef。

          以下代码,如果保存到 max.c,应该对文件顶部的 MAXES #define 中列出的每个单词执行您想要的操作。但是,如果任何 _MAX 值是浮点数,它将不起作用,因为预处理器无法处理浮点数。

          (Boost Processor 是一个方便的工具,但它并不十分简单;您可以决定这种方法是否比复制粘贴更好。)

          #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
          

          【讨论】:

            【解决方案6】:

            没有简单的方法可以做到这一点。最接近的方法是#define 大量 IFDEF 宏,例如:

            #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
            
                 :
            

            因为你需要很多(而且它们可能在多个地方都有用),所以它很重要 将所有这些都粘贴在它们自己的头文件“ifdefs.h”中是有意义的,您可以在需要它们时将其包含在内。您甚至可以编写一个脚本,从 “感兴趣的宏”列表

            然后,你的代码就变成了

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

            【讨论】:

              【解决方案7】:

              只要您只对整数值感兴趣,并假设硬件使用 2 的补码和 8 位字节:

              // 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))
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-06-22
                • 1970-01-01
                • 1970-01-01
                • 2016-12-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多