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

在标准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_ ## tt; 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技术与该库一起工作。

实际上,没有。

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

所有宏替换都在调用宏时发生。

我建议使用Boost.Preprocessor库来自动生成代码。 这有点工作,但你可以使用它完成一些相当令人印象深刻的事情 。 它应该与C完全兼容。

有一种方法!

使用新的_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不起作用,也许它不是在不同的机器上。 我确实让它使用了给出的代码

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

Interesting Posts