2009-07-16 106 views
93

內聯函數與預處理器宏有什麼不同?內聯函數vs預處理器宏

+3

我將此標記爲家庭作業,雖然它可能是一個合法的問題。到目前爲止,你所有的問題都像家庭作業問題一樣,其中一個問題就這樣封閉了。 – 2009-07-16 13:40:27

+0

回答http://stackoverflow.com/questions/132738/why-should-i-ever-use-inline-code包含一些與您的問題相關的信息。 – 2009-07-16 14:55:16

回答

108

預處理器宏只是應用於您的代碼的替代模式。它們幾乎可以在代碼中的任何地方使用,因爲在任何編譯開始之前,它們都會被擴展替換。

內聯函數是其實體直接注入其調用站點的實際函數。它們只能用於函數調用適當的地方。

現在,只要使用宏主場迎戰函數樣的背景下內聯函數,請注意:

  • 宏不是類型安全的,並且可以不管他們是否是正確syntatically擴大 - 編譯階段將報告由宏擴展問題導致的錯誤。
  • 宏可用於您不期望的上下文中,導致出現問題
  • 宏更靈活,因爲它們可以擴展其他宏 - 而內聯函數不一定這樣做。
  • 宏由於其擴展可能會導致副作用,因爲無論輸入表達式出現在模式中何處,它們都會被複制。
  • 內聯函數並不總是保證內聯 - 有些編譯器僅在發佈版本中或在專門配置時才這樣做。而且,在某些情況下內聯可能不可行。
  • 內聯函數可以爲變量提供範圍(特別是靜態變量),預處理宏只能在代碼塊{...}中執行此操作,並且靜態變量的行爲方式不會完全相同。
+26

內聯函數並不總是保證內聯:因爲編譯器不會內聯,如果這樣做會產生較慢的代碼等。編譯器會進行大量的分析工程師不能做並做正確的事情。 – 2009-07-16 16:20:45

+10

我相信遞歸函數是大多數編譯器忽略內聯的另一個例子。 – LBushkin 2009-07-16 17:57:57

11

關鍵的區別是類型檢查。編譯器將檢查你作爲輸入值傳遞的是可以傳遞給函數的類型。預處理器宏並非如此 - 它們在任何類型檢查之前都會擴展,並且可能導致嚴重且難以檢測到的錯誤。

Here是其他幾個不太明顯的概述。

1

內聯functuion在語法上的行爲就像一個正常的函數一樣,爲函數局部變量提供類型安全性和範圍,並且如果是方法,則爲類成員提供訪問權限。 另外,當調用內聯方法時,您必須遵守私有/受保護的限制。

2

內聯函數將維護數值語義,而預處理器宏只複製語法。如果多次使用參數,可以使用預處理器宏獲得非常微妙的錯誤 - 例如,如果參數包含像「i ++」這樣的具有執行兩次的突變,這是相當令人驚訝的。內聯函數不會有這個問題。

8

宏忽略名稱空間。這使他們變得邪惡。

63

首先,預處理器宏只是在編譯之前的代碼中「複製粘貼」。因此,有沒有類型檢查,有的副作用可以出現

例如,如果要比較兩個值:

#define max(a,b) ((a<b)?b:a) 

效果出現在側面,如果您例如使用max(a++,b++)ab將遞增兩次)。 相反,使用(例如)

inline int max(int a, int b) { return ((a<b)?b:a); } 
0

在GCC(我不知道別人),聲明一個內聯函數,僅僅是一個暗示,編譯器。編譯器在一天結束時仍然要決定是否在函數被調用時包含函數的主體。

在行功能和預處理宏之間的差比較大。預處理器宏在一天結束時只是文本替換。您放棄了編譯器執行檢查參數和返回類型類型檢查的許多功能。對參數的評估是非常不同的(如果你傳遞給函數的表達式有副作用,那麼調試時你會覺得很有趣)。關於函數和宏的使用位置有細微的差別。例如,如果我有:

#define MACRO_FUNC(X) ... 

凡MACRO_FUNC顯然定義函數體。特別注意需要採取所以它在所有情況下可以使用的功能正常運行,例如寫得不好MACRO_FUNC將在

if(MACRO_FUNC(y)) { 
...body 
} 

正常功能造成錯誤可能沒有問題,有使用。

9

爲了另一個區別添加到已經給出的:你不能踩通過在調試器#define,但你可以通過一個內聯函數步驟。

0

從編碼的角度來看,內聯函數是像的功能。因此,內聯函數和宏之間的差異與函數和宏之間的差異相同。

從編譯的角度來看,內聯函數類似於宏。它被直接注入到代碼中,而不是被調用。

在一般情況下,你應該考慮內聯函數,以便與混合一些小的優化常規功能,而且最喜歡的優化,它是由編譯器來決定它是否真正關心應用它。通常,編譯器會高興地忽略程序員爲了內聯函數而進行的任何嘗試,出於各種原因。

3

內聯函數類似於宏(因爲該函數的代碼在編譯時調用的點擴展),內聯函數是由編譯器解析,而宏由預處理器擴展。因此,有幾個重要的區別:

  • 內聯函數遵循所有在正常函數上執行的類型安全協議。
  • 內聯函數使用與任何其他函數相同的語法來指定,除了它們在函數聲明中包含內聯關鍵字。
  • 將作爲參數傳遞給內聯函數的表達式評估一次。
  • 在某些情況下,作爲參數傳遞給宏的表達式可以多次計算。 http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • 宏在預編譯時展開,您不能將它們用於調試,但可以使用內聯函數。

-- good article: http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

0

如果內聯函數中存在任何迭代語句或遞歸語句,就會像函數調用一樣工作,以防止重複執行指令。它對保存程序的整體內存非常有幫助。

12

內聯函數是由其中的宏是由預處理器,這是單純的文本substitution.Hence

  • 有宏調用期間沒有類型檢查,而類型檢查過程中完成擴大了編譯器擴展函數調用。

  • 由於重新評估論據和操作順序,宏觀擴展期間可能會出現不希望的結果和效率低下。例如

    #define MAX(a,b) ((a)>(b) ? (a) : (b)) 
    int i = 5, j = MAX(i++, 0); 
    

    將導致

    int i = 5, j = ((i++)>(0) ? (i++) : (0)); 
    
  • 的宏參數宏擴展

    #define MUL(a, b) a*b 
    int main() 
    { 
        // The macro is expended as 2 + 3 * 3 + 5, not as 5*8 
        printf("%d", MUL(2+3, 3+5)); 
    return 0; 
    } 
    // Output: 16` 
    
  • return關鍵字不能在宏中使用的返回值作爲前不被評估功能的情況。

  • 內聯函數可以被重載

  • 傳遞給宏令牌可使用操作者##稱爲令牌粘貼操作符連接。

  • 宏通常用於代碼重用,其中內聯函數用於消除函數調用期間的時間開銷(超時)(避免跳轉到子例程)。