我可以附加到预处理器宏吗?

时间:2010-12-28 22:34:19

标签: c macros c-preprocessor boost-preprocessor x-macros

在标准C或GNU扩展中是否有任何方法可以将内容附加到宏定义中? 例如,给定一个定义为
的宏 #define List foo bar
我可以追加bas以便它List扩展,就好像我已定义它一样 #define List foo bar bas

我希望我能做到这样的事情:

#define List    foo bar bas

#define List_   Expand(List)
#undef List
#define List    Expand(List_) quux

但我无法弄清楚如何定义Expand()宏,以便它能够按照我的意愿行事。

动机: 我正在沿着以下方面玩歧视/标记的工会:

struct quux_foo { int x; };
struct quux_bar { char *s; };
struct quux_bas { void *p; };

enum quux_type {quux_foo, quux_bar, quux_bas};

struct quux {
    enum quux_type type;
    union {
        struct quux_foo foo;
        struct quux_bar bar;
        struct quux_bas bas;
    } t;
};

我认为这是X-macro的好地方。如果我定义一个宏
#define quux_table X(foo) X(bar) X(bas)
枚举&结构可以这样定义,永远不会失去同步:

#define X(t) quux_ ## t,
enum quux_type {quux_table};
#undef X

#define X(t) struct quux_ ## t t;
struct quux {
    enum quux_type type;
    union {quux_table} t;
};
#undef X

当然,quux_*结构可能会失去同步,所以我想做这样的事情,只是合法的:

struct quux_foo { int x; };
#define quux_table quux_table X(foo)

struct quux_bar { char *s; };
#define quux_table quux_table X(bar)

struct quux_bas { void *p; };
#define quux_table quux_table X(bas)

(嗯,我 希望能够做的事情就像是 member_struct(quux, foo) { int x; };
但是我很清楚宏不能从宏中重新定义。)

无论如何,这是我的动力榜样。有没有办法实现这个目标?

Boost.Preprocessor示例很好,如果你能告诉我如何使X-macro技术与该库一起工作。

3 个答案:

答案 0 :(得分:6)

实际上,没有。

宏被懒惰地评估。当您#define List_ Expand(List)时,其替换列表是四个令牌Expand(List)的序列。没有任何方法可以将宏扩展为替换列表。

调用宏时会发生所有宏替换。

我建议使用Boost.Preprocessor库来自动生成代码。这有点工作,但你可以使用它完成一些fairly impressive things。它应与C完全兼容。

答案 1 :(得分:4)

有办法!

使用新的_Pragma关键字可以在gcc中实现(虽然不是用msvc)

如果你在它自己的定义中弹出一个宏,它将延迟它的扩展,直到宏第一次扩展。这允许您使其成为自己定义的先前扩展部分。但是,由于它在扩展期间弹出,因此只能使用一次

以下是一些示例代码,可以看到它的实际效果

#define pushfoo _Pragma("push_macro(\"foo\")") //for convenience
#define popfoo _Pragma("pop_macro(\"foo\")")

#define foo 1

pushfoo                           //push the old value
#undef foo                        //so you don't get a warning on the next line
#define foo popfoo foo , 2        //append to the previous value of foo

pushfoo
#undef foo
#define foo popfoo foo , 3

pushfoo
#undef foo
#define foo popfoo foo , 4


foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4
    //which will in turn expand to 1 , 2 , 3 , 4

foo //the second time this will expand to just 1

此选项应该使自动代码生成更容易,但不幸的是只在gcc上(可能是clang,尚未测试)

说实话,没有理由我可以找到为什么这必须起作用,很可能是未定义的行为恰好起作用。我猜测的原因是,在弹出foo之后,当前正在扩展的宏不再与名称foo相关联,这允许扩展符号foo,但这只是我猜想的

编辑:

在对clang进行测试后,这个不会对clang起作用。

我不知道为什么我认为clang不起作用,也许它不是在另一台机器上。我确实通过

给出了代码

答案 2 :(得分:2)

我不确定这是否有帮助,但你可以做vari arg宏。 x264项目的康拉德先生喜欢预处理器滥用。如果他们听起来可能有所帮助,您可以找到更多Here