11

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

4

3 回答 3

11

有一种方法!

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

于 2017-08-18T16:48:48.257 回答
7

实际上,没有。

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

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

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

于 2010-12-30T19:16:22.793 回答
2

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

于 2010-12-28T22:48:05.120 回答