我可以附加到预处理器宏吗?
标准 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 宏的好地方。如果我定义一个宏#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 宏技术与该库一起使用。
Is there any way in standard C—or with GNU extensions—to append stuff to a macro definition? E.g., given a macro defined as#define List foo bar
can I append bas
so that it List
expands as if I’d defined it#define List foo bar bas
?
I was hoping I could do something like this:
#define List foo bar bas
#define List_ Expand(List)
#undef List
#define List Expand(List_) quux
but I can’t figure out how to define the Expand()
macro so it’ll do what I want.
Motivation:
I’m playing with discriminated/tagged unions along these lines:
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;
};
I figure this is a good place for the X-macro. If I define a macro#define quux_table X(foo) X(bar) X(bas)
the enumeration & structure can be defined thus, and never get out of sync:
#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
Of course, the quux_*
structures can get out of sync, so I’d like to do something like this, only legally:
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)
(Well, what I really want to be able to do is something likemember_struct(quux, foo) { int x; };
but I’m well aware that macros cannot be (re)defined from within macros.)
Anyhow, that’s my motivating example. Is there a way to accomplish this?
Boost.Preprocessor examples are fine, if you can show me how to make the X-macro technique work with that library.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不确定这是否有帮助,但您可以执行 vari arg 宏。 x264 项目的 Conrad 先生喜欢滥用预处理器。如果它们听起来可能有帮助,您可以在此处了解更多信息
I'm not sure if this helps, but you can do vari arg macros. Mr. Conrad of the x264 project loves preprocessor abuse. If they sound like they might help you can find out more Here
有办法!
使用新的 _Pragma 关键字,这可以在 gcc 中实现(尽管不能使用 msvc)。
如果您在其自己的定义中弹出一个宏,它将延迟其扩展,直到该宏第一次扩展为止。这允许您将其先前的扩展部分作为其自己的定义。然而,由于它在扩展过程中被弹出,所以只能使用一次
这里有一些示例代码来查看它的实际情况
这个选项应该使自动代码生成变得更加容易,尽管不幸的是仅在 gcc 上(也许 clang,还没有测试过)
说实话,我没有理由可以找到为什么这必须起作用,很可能是未定义的行为恰好起作用。我猜测原因是在弹出 foo 之后,当前正在扩展的宏不再与名称 foo 关联,这允许扩展符号 foo ,但这只是我的猜想
编辑:
之后在 clang 上测试,这个
不在 clang 上工作。我不知道为什么我认为 clang 不起作用,也许它在不同的机器上不起作用。我确实让它与给出的代码一起工作
There is a way!
Using the new _Pragma keyword this can be achieved in gcc (though not with msvc)
If you pop a macro within it's own definition it will delay it's expansion until the macro is expanded for the first time. This allows you to make it's previous expansion part of it's own definition. However, since it is popped during it's expansion, it can only be used once
Here is some sample code to see it in action
This option should make automatic code generation a fair bit easier, though unfortunately only on gcc (maybe clang, haven't tested)
To be honest there is no reason I can find why this must work, it is most probably undefined behavior that happens to work. I'm guessing the reason is that after popping foo, the current macro being expanded is no longer associated with the name foo which allows the symbol
foo
to be expanded, but that is only my conjectureEdit:
After testing on clang, this
does notdoes work on clang.I don't know why I thought clang did not work, maybe it didn't on a different machine. I definitely did get it to work with the code given though
实际上,不。
宏是延迟求值的。当您
#define List_ Expand(List)
时,其替换列表是四个标记Expand
、(
、List
的序列代码>和<代码>)。没有任何方法可以将宏扩展为替换列表。所有宏替换都在调用宏时发生。
我建议使用 Boost.Preprocessor 库来自动生成代码。这是一项工作,但您可以完成一些相当令人印象深刻的事情。它应该与C完全兼容。
Effectively, no.
Macros are lazily evaluated. When you
#define List_ Expand(List)
, its replacement list is the sequence of four tokensExpand
,(
,List
, and)
. There isn't any way to expand a macro into a replacement list.All macro replacement takes place when a macro is invoked.
I'd recommend looking at using the Boost.Preprocessor library for automatic code generation. It's a bit of work, but you can accomplish some fairly impressive things using it. It should be fully compatible with C.