5

我正在寻找一个类似于 with-construct 的宏。用法应该是这样的:

with (lock(&x), unlock(&x)) {
    ...
}

它可能对其他一些目的有用。

我想出了这个宏:

#define __with(_onenter, _onexit, v) \
    for (int __with_uniq##v=1; __with_uniq##v > 0; )\
        for (_onenter; __with_uniq##v > 0; _onexit) \
            while (__with_uniq##v-- > 0)

#define _with(x, y, z) __with(x, y, z)
#define with(_onenter, _onexit) _with(_onenter, _onexit, __COUNTER__)

它有 3 个嵌套循环,因为它应该:

  1. 初始化循环计数器(当然,仅限 C99)
  2. 可能初始化变量_onenter(例如with (int fd=open(..), close(fd))
  3. 允许break在代码块内。(continue也是允许的。宏可以调整assert()出来)

我在 XV6 OS 的代码中使用了它,它看起来非常有用。

我的问题是 - 这种宏最严重的问题是什么?我的意思是,除了仅使用 C 宏(尤其是实现新控制流构造的宏)之外。

到目前为止已经发现了这些缺点/问题:

  1. 不支持returnor goto(但它可以goto在内核代码中节省一些 s)
  2. 不支持错误(例如fd < 0)。我认为这个是可以修复的。
  3. 仅限 gnu89 / c99 及更高版本(循环计数器。不需要唯一变量技巧)
  4. 比简单的锁定解锁效率要低一些。我相信它是微不足道的。

还有其他问题吗?有没有更好的方法在 C 中实现类似的构造?

4

1 回答 1

6

那个宏吓到我了。我更喜欢使用s的传统方法goto

这种方法是原始的,但大多数 C 程序员都熟悉这种模式,如果他们不熟悉,他们可以通过阅读本地代码来理解它。没有隐藏的行为。因此,它非常可靠。

你的宏很聪明,但它对大多数人来说都是新的,它带有隐藏的陷阱。必须考虑新贡献者的规则,例如“不要returngoto脱离 with 块”和“break将脱离 with 块,而不是脱离周围的循环”。我担心错误会很常见。

如果您可以向编译器添加有关滥用此构造的警告,那么平衡将会发生变化。使用 clang,这似乎是一种选择。在这种情况下,将检测到误用,并且您的代码将保持可移植到其他编译器。

如果您愿意将自己限制为 GCC 和 Clang,则可以使用该cleanup属性。这将使您的示例如下所示:

lock_t x = NULL __attribute__((cleanup(unlock)));
lock(&x);

unlock当它超出范围时,将使用指向该变量的指针来调用它。这与其他语言功能集成,例如returnand goto,甚至在混合 C/C++ 项目中也有例外。

于 2013-04-28T11:35:00.370 回答