【问题标题】:How can I generate a list via the C preprocessor (cpp)?如何通过 C 预处理器 (cpp) 生成列表?
【发布时间】:2011-02-05 00:27:33
【问题描述】:

我想做如下的事情:

F_BEGIN

F(f1) {some code}
F(f2) {some code}
...
F(fn) {some code}

F_END

并让它生成以下内容

int f1() {some code}
int f2() {some code}
...
int fn() {some code}

int (*function_table)(void)[] = { f1, f2, ..., fn };

函数本身很简单。我似乎无法做的是跟踪所有名称,直到 function_table 结束。

我查看了this questionthis question,但我无法为我工作。 有什么想法吗?

【问题讨论】:

    标签: c c-preprocessor


    【解决方案1】:

    使用预处理器执行此操作的常规方法是在一个宏中定义所有函数,该宏将另一个宏作为参数,然后使用其他宏来提取您想要的内容。以您为例:

    #define FUNCTION_TABLE(F) \
        F(f1, { some code }) \
        F(f2, { some code }) \
        F(f3, { some code }) \
    :
    
        F(f99, { some code }) \
        F(f100, { some code })
    
    #define DEFINE_FUNCTIONS(NAME, CODE)     int NAME() CODE
    #define FUNCTION_NAME_LIST(NAME, CODE)   NAME,
    
    FUNCTION_TABLE(DEFINE_FUNCTIONS)
    int (*function_table)(void)[] = { FUNCTION_TABLE(FUNCTION_NAME_LIST) };
    

    【讨论】:

    • C 预处理器不允许宏定义其他宏,也不允许使用任何方法进行递归或循环,因此这种技术(也由 ddyer 描述)是您能做到的最好的去做。
    【解决方案2】:

    如果您有符合 C99 的编译器,则预处理器具有可变长度参数列表。 P99 有一个预处理器 P99_FOR 可以像您想要实现的那样进行“代码展开”。贴近你的榜样

    #define MYFUNC(DUMMY, FN, I) int FN(void) { return I; } 
    #define GENFUNCS(...)                                          \
    P99_FOR(, P99_NARG(__VA_ARGS__), P00_IGN, MYFUNC, __VA_ARGS__) \
    int (*function_table)(void)[] = { __VA_ARGS__ }
    
    GENFUNCS(toto, hui, gogo);
    

    将扩展为以下(未经测试)

    int toto(void) { return 0; } 
    int hui(void) { return 1; }
    int gogo(void) { return 2; }
    int (*function_table)(void)[] = { toto, hui, gogo };
    

    【讨论】:

      【解决方案3】:

      这是对 CPP 的一种滥用,但却是一种常见的滥用。我处理情况 像这样通过定义虚拟宏

      #define FUNCTIONS \
       foo(a,b,c,d) \
       foo(a,b,c,d) \
       foo(a,b,c,d)
      
      now, 
      
      #define foo(a,b,c,d) \
       a+b ;
      
      FUNCTIONS
      
      #undef foo
      

      以后,当你想用同一个列表做不同的事情时

      #define foo(a,b,c,d) \
       a: c+d ;
      
      FUNCTIONS
      
      #undef foo
      

      它有点丑陋和麻烦,但它确实有效。

      【讨论】:

      • 如果你将foo 作为FUNCTIONS 的参数而不是到处乱用PHP,那就不那么难看了。
      【解决方案4】:

      有一个叫做X Macro的东西被用作:

      一种可靠维护并行列表、代码或数据的技术,其对应的项目必须以相同的顺序出现

      这就是它的工作原理:

          #include <stdio.h>
      
      //you create macro that contains your values and place them in (yet) not defined macro
      #define COLORS\
          X(red, 91)\
          X(green, 92)\
          X(blue, 94)\
      
      //you can name that macro however you like but conventional way is just an "X"
      
      //and then you will be able to define a format for your values in that macro
      #define X(name, value) name = value,
      typedef enum { COLORS } Color;
      #undef X //so you redefine it below
      
      int main(void)
      {
          #define X(name, value) printf("%d, ", name);
          COLORS
          #undef X
          return 0;
      }
      

      您的问题的解决方案是:

      #define FUNCTIONS \
      F(f1, code1)\
      F(f2, code2)\
      F(f3, code3)
      
      #define F(name, code) int name(void){code}
      FUNCTIONS
      #undef F
      
      
      #define F(name, code) &name,
      int (*function_table[])(void) = { FUNCTIONS };
      #undef F
      

      【讨论】:

        【解决方案5】:

        Boost 是一个 C++ 库,但它的 Preprocessor 模块应该仍然适合在 C 中使用。它提供了一些令人惊讶的高级数据类型和用于预处理器的功能。你可以去看看。

        【讨论】:

        • 我想只用 cpp 来做这个。
        • Boost::Preprocessor 是纯C Pre-Processor(以及C++ Pre-Processor)。
        猜你喜欢
        • 2020-10-09
        • 2019-07-12
        • 2011-09-23
        • 2010-11-11
        • 2022-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多