2013-07-12 18 views
1

我有一些簡單的功能,如更好的是:函數或定義

#define JacobiLog(x1,x2) ((x1>x2)?x1:x2)+log(1+exp(-fabs(x1-x2))) 

什麼是更好地執行(代碼,編譯,記憶...) - 如上定義,或者寫一些簡單的功能

double JacobiLog(double x1,double x2) 
{ 
    return ((x1>x2) ? x1 : x2) + log(1+exp(-fabs(x1-x2))); 
} 
+0

函數返回可以創建返回變量的另一個副本。可能會更慢。也許使用&可以擺脫它。 –

回答

0

define可以可能是快一點,但最有可能的編譯器無論如何都會內聯函數(或者你可以爲內聯標記),他們將是相同的。但功能更好,因爲它更易讀,更易於調試。

0

功能是更好,假設一個好的編譯器。

使用該函數,編譯器判斷代碼是否內聯(假設函數的定義可供所有使用它的人員使用,例如,如果它是在頭中聲明的inline函數C++,或者只是一個普通函數,其所有用戶都在同一個翻譯單元中)。使用宏,它總是內聯的,這不一定更快,因爲它可能導致代碼膨脹,並因此導致更多的緩存未命中和頁面錯誤。

更不用說宏很難閱讀,甚至更難以調試。

+0

「更好」是有點含糊,它通常不依賴於編譯器,因爲我們正在討論微觀優化。就我所知,「內聯」只是一個編譯器提示。編譯器可以自由地忽略它,或內聯任何非'inline'函數,受內聯能力的限制。 – Dukeling

+0

我提到'inline',因爲它需要在不違反ODR的情況下在頭文件中定義函數,而不是因爲它影響了編譯器內聯代碼的能力。它不,它確實只是一個暗示。 因爲'better'含糊不清,所以我用斜體表示。 –

0

即使'define'更快(因爲它阻止了函數調用),編譯器可以優化並內聯你的函數,並使其快速。

如果您處於C++環境中,您應該始終使用模板和函數。它會讓你的程序更具可讀性並防止類型錯誤。

在C中,因爲沒有指定類型宏可能是有用的(參見下面的示例):

/* Will work with int, long, double, short, etc. */ 
#HIGHER(VAL1, VAL2) ((VAL1) > (VAL2) ? (VAL1) : (VAL2)) 
2

編譯器可能會自動設定功能爲內嵌。你應該使用它而不是定義。

這也將避免在您使用的情況下意外的行爲舉止的定義爲

double num = JacobiLog(x++, y++); 

我讓你想象的代碼替換問題...

0

這是一個微型優化。除非你正在做嵌入式編程和每一個指令,否則請使用該函數。更不用說log可能比調用函數的開銷慢100倍。所以如果你的程序主要是調用這個函數,你只能節約1%。 [1]一旦你的程序開始做其他重要的事情,這種節約將減少到基本上不明顯。

只要有可能,編譯器可以自由地內聯函數,這會使兩者完全相同。但是,您不能強制編譯器這樣做。在C++中有一個inline關鍵字,但這只是一個提示,編譯器可以自由地忽略它。

請參閱this瞭解兩者之間的一些差異(這涵蓋了內嵌函數與非內聯函數,但是,如上所述,內聯函數基本上與#define相同)。鏈接的基本結論是「取決於」。

另請注意,行爲上,a #define and a function are not 100% equivalent


[1]:圖很大程度上彌補。基準,如果你想要準確的結果。

0

首先(爲了一個完整的答案),我們必須承認,使用宏可能會產生令人驚訝的副作用,您可能不打算這樣做,並且函數確保您知道傳入類型,並且知道每個參數都被評估恰好一次。

使用宏的這些效果往往是問題的根源。

通常,編譯器會根據需要內聯函數,並且如果它的工作正確,那麼它應該具有宏的幾乎所有優點,但沒有罕用的副作用。

雖然有時您可以獲得內聯編譯器可能無法識別的一些好處。例如,如果您的宏將intlong轉換爲double,並且在整數運算(可能具有性能或精度優勢)中執行更多操作,則您的宏將暫時將參數轉換爲double。你也可能會得到整數溢出和不正確的結果。由於您在「更好」因素列表中包含了「內存」,因此很容易認爲該函數較小(假設您將編譯器配置爲針對大小進行優化),但這不一定是正確的。

顯然作爲一個函數,你只需要在內存中的一個副本,所有的調用者都可以使用相同的代碼,而在每次使用時內聯或擴展重複代碼。您的編譯器不太可能將宏分離出來,並將其轉換爲從代碼中許多不同位置調用的函數。

未定義函數可能無法縮小的地方在於它的簡化方式。有三種常見的情況下,我能想到的:

  1. 如果所有功能的使用都涉及常量參數,內聯簡化出來會比原來的全功能小。
  2. 使用正確寄存器中的參數執行函數調用所需的寄存器編組代碼可能比函數本身更長。
  3. 添加一個函數調用可以增加調用者的註冊壓力,迫使它產生更復雜的代碼,可能迫使它創建一個棧幀並在進入和退出時保存更多的寄存器。
相關問題