2009-10-15 21 views
9

According to the C FAQ不同的宏功能/內聯方法缺點,基本上有用於C「內聯」代碼3種的實用方法:優點和在c

#define MACRO(arg1, arg2) do { \ 
    /* declarations */ \ 
    stmt1; \ 
    stmt2; \ 
    /* ... */ \ 
    } while(0) /* (no trailing ;) */ 

#define FUNC(arg1, arg2) (expr1, expr2, expr3) 

爲了澄清這一個,參數用在表達式中,並且逗號運算符返回最後一個表達式的值。

使用inline聲明其被支撐爲extension to gcc and in the c99 standard

do { ... } while (0)方法在Linux內核中被廣泛使用,但是我還沒有經常遇到其他兩種方法。

我特指多語句「函數」,而不是像MAX或MIN這樣的單個語句。

每種方法的優缺點是什麼,爲什麼你會在各種情況下選擇一種?

+0

中間示例沒有多大意義,宏使用名爲arg1和arg2的參數,並且在宏體中使用expr1,expr2和expr3 ? – unwind 2009-10-15 10:06:40

+1

它是有道理的,因爲'argN'可以嵌套在右側的子表達式中。像'(arg1^= arg2,arg2^= arg1,arg1^= arg2)',我想。 – 2009-10-15 10:10:11

+3

除非你測量了你的代碼並知道你需要優化,否則不要打擾:爲所有事情編寫正常的函數。 – pmg 2009-10-15 10:12:12

回答

16

談論具體的使用宏,即宏充當「功能」,我想提的宏不能在一個內聯函數有以下優點:

懶惰的說法評價。例如,像這樣的

#define SELECT(f, a, b) ((f) ? (a) : (b)) 

宏將維持三元運算的懶惰參數評價特性:只對選定參數進行評估,而其他則不是。直接的內聯函數模擬將事先評估兩個參數,從而做了額外的不必要的工作。

訪問上下文。宏可用於實現「本地函數」的某些相似性,即可訪問局部變量和封閉函數參數的重複代碼段。

類型獨立性(和類型參數)。宏允許您編寫與類型無關的「函數」(請參見上面的示例)。並且,如果您無法擺脫類型依賴性,則可以將類型作爲參數傳遞給宏。

上面提到的作爲專業人士提供的宏的屬性可能會被濫用導致重大失敗(因此也可能被視爲缺點)。但是這可以說是C中的許多語言功能。

+0

+1這些都是好點。 – 2009-10-15 11:14:51

+1

在一個像#define MAX(A,B)((A)>(B)?(A):(B))的例子中,如果A或B包含一個動作(如i ++),它甚至是最糟糕的,因爲它會評估兩次。 – eyalm 2009-10-15 12:50:13

+0

@AndreyT:也許你可以解釋一些這些缺點? – 2009-10-15 13:58:08

0

我可以看到使用任何結構的唯一職業是讓它更快的代碼。

因此,選擇一種給出最快代碼的方法!

如果這一切都一樣,那麼我覺得它更清晰

  1. 「標準」的功能
  2. 一個inline功能
  3. #define ... do {} while(0)方法
  4. 用逗號宏分隔的表達式
5

使用inline關鍵字的一個親是你可以檢查通過函數原型的參數。使用宏你不會得到任何類似的東西,所以如果你把錯誤類型的東西放在它們中,宏很容易產生奇怪的錯誤。 (雖然不像C++中的模板錯誤那麼可怕)。

使用宏的一個親是你可以做一些時髦的事情,比如連接和使用#arg將宏參數變成一個字符串。使用預處理器宏的另一個好處是你可以很容易地檢查它們如何使用cpp展開以展開它們。這是你如何調試這些錯誤。

宏定義函數的另一個有用的地方是,如果需要,您可以將return語句粘貼到它們中以暫停父函數。使用內聯函數,您必須返回一個值,然後檢查返回值。

+0

實際上,我有一種希望函數模板在C中可用。那樣您可以通過函數的類型安全性來獲得宏的靈活性。 – 2009-10-15 14:18:04

+0

@ RobertS.Barnes,它被稱爲C有一個原因 – Pacerier 2013-09-27 09:25:13