当前位置:  开发笔记 > 编程语言 > 正文

可以使用代码块作为C宏的参数吗?

如何解决《可以使用代码块作为C宏的参数吗?》经验,为你挑选了2个好方法。

我有一个模式,基本上是一些样板代码,其中一部分在中间变化

if(condition){
    struct Foo m = start_stuff();
    { m.foo = bar(1,2); m.baz = 17; } //this part varies
    end_stuff();
}

是否可以使宏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;
});

到目前为止,我设法想到的唯一一件事就是如果我在宏中使用循环语句breakcontinue被捕获,这对我的特定用例来说是一个可接受的权衡.

编辑:当然,如果可以的话,我会使用一些功能.我在这个问题中使用的示例是简化的,并没有展示只能用于宏魔术的位.



1> rici..:

您可以将代码块放入宏参数中,前提是它没有无防护的逗号.在您的示例中,参数中唯一的逗号被保护,因为它被括号括起来.

请注意,只有括号保护逗号.括号([])和括号({})没有.


显然,无论您如何称呼它们:`<>`(尖括号?)都不是。发现这一点试图使用带有多个模板参数的代码

2> Eric Julien..:

另外,您可以考虑使用复合语句之前的宏,如下所示。优点之一是,所有调试器仍将能够进入您的复合语句,而使用复合声明作为宏参数方法则不是这种情况。

//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();}

我使用“ condition”作为宏参数,但是如果需要,您也可以将其直接嵌入宏中。

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有