我有一些簡單的功能,如更好的是:函數或定義
#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)));
}
我有一些簡單的功能,如更好的是:函數或定義
#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)));
}
define
可以可能是快一點,但最有可能的編譯器無論如何都會內聯函數(或者你可以爲內聯標記),他們將是相同的。但功能更好,因爲它更易讀,更易於調試。
功能是更好,假設一個好的編譯器。
使用該函數,編譯器判斷代碼是否內聯(假設函數的定義可供所有使用它的人員使用,例如,如果它是在頭中聲明的inline
函數C++,或者只是一個普通函數,其所有用戶都在同一個翻譯單元中)。使用宏,它總是內聯的,這不一定更快,因爲它可能導致代碼膨脹,並因此導致更多的緩存未命中和頁面錯誤。
更不用說宏很難閱讀,甚至更難以調試。
「更好」是有點含糊,它通常不依賴於編譯器,因爲我們正在討論微觀優化。就我所知,「內聯」只是一個編譯器提示。編譯器可以自由地忽略它,或內聯任何非'inline'函數,受內聯能力的限制。 – Dukeling
我提到'inline',因爲它需要在不違反ODR的情況下在頭文件中定義函數,而不是因爲它影響了編譯器內聯代碼的能力。它不,它確實只是一個暗示。 因爲'better'含糊不清,所以我用斜體表示。 –
即使'define'更快(因爲它阻止了函數調用),編譯器可以優化並內聯你的函數,並使其快速。
如果您處於C++環境中,您應該始終使用模板和函數。它會讓你的程序更具可讀性並防止類型錯誤。
在C中,因爲沒有指定類型宏可能是有用的(參見下面的示例):
/* Will work with int, long, double, short, etc. */
#HIGHER(VAL1, VAL2) ((VAL1) > (VAL2) ? (VAL1) : (VAL2))
編譯器可能會自動設定功能爲內嵌。你應該使用它而不是定義。
這也將避免在您使用的情況下意外的行爲舉止的定義爲
double num = JacobiLog(x++, y++);
我讓你想象的代碼替換問題...
這是一個微型優化。除非你正在做嵌入式編程和每一個指令,否則請使用該函數。更不用說log
可能比調用函數的開銷慢100倍。所以如果你的程序主要是調用這個函數,你只能節約1%。 [1]一旦你的程序開始做其他重要的事情,這種節約將減少到基本上不明顯。
只要有可能,編譯器可以自由地內聯函數,這會使兩者完全相同。但是,您不能強制編譯器這樣做。在C++中有一個inline
關鍵字,但這只是一個提示,編譯器可以自由地忽略它。
請參閱this瞭解兩者之間的一些差異(這涵蓋了內嵌函數與非內聯函數,但是,如上所述,內聯函數基本上與#define
相同)。鏈接的基本結論是「取決於」。
另請注意,行爲上,a #define
and a function are not 100% equivalent。
[1]:圖很大程度上彌補。基準,如果你想要準確的結果。
首先(爲了一個完整的答案),我們必須承認,使用宏可能會產生令人驚訝的副作用,您可能不打算這樣做,並且函數確保您知道傳入類型,並且知道每個參數都被評估恰好一次。
使用宏的這些效果往往是問題的根源。
通常,編譯器會根據需要內聯函數,並且如果它的工作正確,那麼它應該具有宏的幾乎所有優點,但沒有罕用的副作用。
雖然有時您可以獲得內聯編譯器可能無法識別的一些好處。例如,如果您的宏將int
或long
轉換爲double
,並且在整數運算(可能具有性能或精度優勢)中執行更多操作,則您的宏將暫時將參數轉換爲double
。你也可能會得到整數溢出和不正確的結果。由於您在「更好」因素列表中包含了「內存」,因此很容易認爲該函數較小(假設您將編譯器配置爲針對大小進行優化),但這不一定是正確的。
顯然作爲一個函數,你只需要在內存中的一個副本,所有的調用者都可以使用相同的代碼,而在每次使用時內聯或擴展重複代碼。您的編譯器不太可能將宏分離出來,並將其轉換爲從代碼中許多不同位置調用的函數。
未定義函數可能無法縮小的地方在於它的簡化方式。有三種常見的情況下,我能想到的:
函數返回可以創建返回變量的另一個副本。可能會更慢。也許使用&可以擺脫它。 –