2013-04-24 104 views
5

我正在寻找一个类似于with-construct的宏。 的使用应该是这样的:”with“macro in C

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. returngoto(但它可以节省内核代码中的一些goto S)
  2. 错误不支持(如fd < 0)不支持。我认为这是可以修复的。
  3. 仅gnu89/c99及以上版本(循环计数器,不需要独特的可变技巧)
  4. 比简单的锁定解锁效率稍差。我相信这是微不足道的。

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

回答

6

这个宏让我害怕。我更喜欢traditional approach using gotos

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

你的宏很聪明,但它对大多数人来说都是新的,它带有隐藏的陷阱。新的贡献者将不得不被认为是规则,例如“不要使用returngoto”,并且“break将跳出”with block“,而不是跳出周围的循环”。我担心错误会很常见。

如果您可以向编译器添加错误使用此构造的警告,天平会发生移位。 With clang,这似乎是一个选项。在这种情况下,会检测到误用,并且您的代码将保持可移植到其他编译器。

如果您想限制自己使用GCC和Clang,则可以使用cleanup属性。这将使你的例子是这样的:

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

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

+0

哦。最后回应......谢谢,我不知道“清理” - 听起来很有用。除了它的可怕程度,这个宏还有更具体的问题吗? – Elazar 2013-04-28 11:45:29

+1

缺乏对'return'的支持似乎是一种破坏行为,除非你在函数中间使用严格的编码标准来处理'return'语句。 'with'块中的'return'看起来不显眼,但会在运行时造成严重破坏。 – pdw 2013-04-28 13:31:04

+0

我明白了,同意'return'是一个大问题(所以'清理'要好得多)。但是'goto'不需要同样严格的编码标准吗? goto在这方面有什么优势? – Elazar 2013-04-28 13:47:13