2013-04-24 118 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