我有一个模式,基本上是一些样板代码,其中一部分在中间变化
if(condition){
struct Foo m = start_stuff();
{ m.foo = bar(1,2); m.baz = 17; } //this part varies
end_stuff();
}
Run Code Online (Sandbox Code Playgroud)
是否可以使宏taht将该中间代码块作为参数?C中的宏扩展规则看起来非常复杂,所以我不确定将来是否会出现任何可能出现并且咬我的角落情况(特别是,我不明白如果我的代码如何分离宏参数有逗号).
#define MY_MACRO(typ, do_stuff) do { \
if(condition){ \
struct typ m = start_stuff(); \
do_stuff; \
end_stuff(); \
} \
}while(0)
//usage
MY_MACRO(Foo, {
m.foo = bar(1,2);
m.baz = 17;
});
Run Code Online (Sandbox Code Playgroud)
到目前为止,我设法想到的唯一一件事就是如果我在宏中使用循环语句break而continue被捕获,这对我的特定用例来说是一个可接受的权衡.
编辑:当然,如果可以的话,我会使用一些功能.我在这个问题中使用的示例是简化的,并没有展示只能用于宏魔术的位.
ric*_*ici 16
您可以将代码块放入宏参数中,前提是它没有无防护的逗号.在您的示例中,参数中唯一的逗号被保护,因为它被括号括起来.
请注意,只有括号保护逗号.括号([])和括号({})没有.
另外,您可以考虑使用复合语句之前的宏,如下所示。优点之一是,所有调试器仍将能够进入您的复合语句,而使用复合声明作为宏参数方法则不是这种情况。
//usage
MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}
Run Code Online (Sandbox Code Playgroud)
使用一些goto魔术(是的,在某些情况下'goto'可能是邪恶的,但是在C语言中我们很少有其他选择),可以将宏实现为:
#define CAT(prefix, suffix) prefix ## suffix
#define _UNIQUE_LABEL(prefix, suffix) CAT(prefix, suffix)
#define UNIQUE_LABEL(prefix) _UNIQUE_LABEL(prefix, __LINE__)
#define MY_MACRO(typ, condition) if (condition) { \
struct typ m = start_stuff(); goto UNIQUE_LABEL(enter);} \
if (condition) while(1) if (1) {end_stuff(); break;} \
else UNIQUE_LABEL(enter):
Run Code Online (Sandbox Code Playgroud)
请注意,禁用编译器优化时,这对性能和占用空间的影响很小。同样,调试器在运行调用end_stuff()函数时似乎会跳回到MY_MACRO行,这并不是真正希望的。
另外,您可能希望在新的块范围内使用该宏,以避免使用'm'变量污染范围:
{MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}}
Run Code Online (Sandbox Code Playgroud)
当然,在复合语句的嵌套循环中不使用“ break”会跳过“ end_stuff()”。为了让那些人打破周围的循环并仍然调用'end_stuff()',我认为您必须在复合语句中加上一个开始标记和一个结束标记,如下所示:
#define MY_MACRO_START(typ, condition) if (condition) { \
struct typ m = start_stuff(); do {
#define MY_MACRO_EXIT goto UNIQUE_LABEL(done);} while (0); \
end_stuff(); break; \
UNIQUE_LABEL(done): end_stuff();}
MY_MACRO_START(foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
} MY_MACRO_END
Run Code Online (Sandbox Code Playgroud)
注意,由于该方法的“中断”,MY_MACRO_EXIT宏仅在循环或开关内可用。当不在循环中时,可以使用更简单的实现:
#define MY_MACRO_EXIT_NOLOOP } while (0); end_stuff();}
Run Code Online (Sandbox Code Playgroud)
我使用“ condition”作为宏参数,但是如果需要,您也可以将其直接嵌入宏中。
| 归档时间: |
|
| 查看次数: |
7626 次 |
| 最近记录: |