C中的"with"宏

Ela*_*zar 5 c with-statement c-preprocessor

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

with (lock(&x), unlock(&x)) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

它可能对其他一些用途有用.

我想出了这个宏:

#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__)
Run Code Online (Sandbox Code Playgroud)

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

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

我在XV6操作系统的代码上使用它,它看起来非常有用.

我的问题是 - 这样一个宏的最大问题是什么?我的意思是,除了仅仅使用C宏(特别是实现新的控制流构造的宏).

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

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

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

pdw*_*pdw 6

那个宏吓到我了.我更喜欢使用gotos传统方法.

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

你的宏很聪明,但它对大多数人来说都是新的,它带有隐藏的陷阱.新的贡献者必须被认为是规则,例如"不要returngoto不使用块"和" break将突破with块,而不是从周围的循环中".我担心错误会很常见.

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

如果您愿意将自己限制为GCC和Clang,则可以使用该cleanup属性.这会使你的例子看起来像这样:

lock_t x = NULL __attribute__((cleanup(unlock)));
lock(&x);
Run Code Online (Sandbox Code Playgroud)

并且unlock将与指针变量,当它超出范围被调用.这与其他语言功能(如returngoto,甚至是混合C/C++项目中的例外)集成在一起.