2013-01-05 58 views

回答

1

宏不會進行類型檢查並需要其他特殊的考慮(即只對一個表達式求值一次),所以應儘可能避免它們。但是不檢查類型的優點是允許您在C89中編寫通用函數。

也編寫實際的inline函數允許(使用一個可以在內核配置中激活的特定標誌)編譯器也可以將其取消,如果這具有性能優勢,而這對於宏來說是不可能的,作爲簡單的文本替換。

0

作爲文本替換的宏可以做的不僅僅是內聯函數。他們也可能有不必要的副作用。考慮衆所周知的交換宏。

#define SWAP(a,b) {int t=a; a=b; b=t} 

並指出SWAP(i,t[i])做不必要的事情。

內聯函數具有函數調用類似語義(參數被評估一次等)的優勢。

所以它主要是編碼風格的問題,並認識到宏功能是不同種類的動物。

而你的問題並沒有真正與內核相關。任何C(甚至C++)程序都有相同的問題。

+0

由於內核使用了大量的GCC擴展,如_____attribute_____等。所以我認爲副作用因素不能在考慮範圍內,因爲**語句表達式**可以處理這個問題。請參閱http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Statement-Exprs.html#Statement-Exprs – larmbr

+0

不,GCC擴展並不總是有幫助的(即使它們非常方便) ,正如我簡單的'SWAP'示例所示。 –

+0

至於副作用的東西,我認爲海灣合作委員會擴展是勝任的。但我同意你的看法,主要是編碼風格。 – larmbr

0

請記住,Linux內核中的很多代碼已經存在很長一段時間了。一些宏也會對輸入/環境的其他部分做出「聰明的東西」,而不是函數會/可能/應該做的。

作爲一般規則,儘可能使用(內聯)函數,因爲如上所述,功能的「疑難問題」較少。

如果你做了巧妙的替換或者其他的「只能在宏中做」,那麼在可能的情況下生成一個形成函數參數的宏是非常好的。例如。

#define ASSERT(x) do { if (!(x)) { fprintf(stderr, "Assertion failed on %s:%d", __FILE__, __LINE__); exit(1); } while(0); 

可以做的:

#define ASSERT(x) do_assert(!!(x), __FILE__, __LINE__); 

void do_assert(bool val, const char *file, int line) 
{ 
    if (!val) 
    { 
     fprintf(....); 
     exit(1); 
    } 
} 

現在你可以,例如,在調試版本,在您的斷言設置一個斷點,如果裏面,每當你的斷言失敗了,你可以看到你如何到達那裏。有了宏,這是不可能的。

現代編譯器在適當的情況下做了很好的內聯操作,給了一半的機會。

相關問題