如何通过C预处理器(cpp)生成列表?

时间:2011-02-05 00:27:34

标签: c c-preprocessor

我想做以下事情:

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 };

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

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

5 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:5)

如果您有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 };

答案 2 :(得分:2)

有一个叫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 //just another convention (so you don't use it accidentally, I think)

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

答案 3 :(得分:1)

这是对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

它有点难看和繁琐,但它确实有效。

答案 4 :(得分:0)

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