作为替代方案,您可以考虑在复合语句之前使用宏,如下所示。这样做的优点之一是所有调试器仍然能够进入您的复合语句,而复合语句作为宏参数方法并非如此。
//usage
MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}
使用一些 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):
请注意,当禁用编译器优化时,这对性能和占用空间的影响很小。此外,在运行调用 end_stuff() 函数时,调试器似乎会跳回 MY_MACRO 行,这并不是真正可取的。
此外,您可能希望在新的块范围内使用宏,以避免“m”变量污染您的范围:
{MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}}
当然,不在复合语句的嵌套循环内使用“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
请注意,由于该方法中的“中断”,MY_MACRO_EXIT 宏只能在循环或开关内使用。当不在循环内时,您可以使用更简单的实现:
#define MY_MACRO_EXIT_NOLOOP } while (0); end_stuff();}
我使用“条件”作为宏参数,但如果需要,您也可以将其直接嵌入宏中。