2011-10-13 67 views
4

我有一個關於我的代碼性能的問題。 比方說,我有一個在C結構的一個觀點:ANSI C#define VS函數

typedef struct _CPoint 
{ 
    float x, y; 
} CPoint; 

,並在那裏我用的是結構的函數。

float distance(CPoint p1, CPoint p2) 
{ 
    return sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2)); 
} 

我在想,如果這將是一個聰明的主意,以取代此功能使用#define,

#define distance(p1, p2)(sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2))); 

我認爲這將是更快,因爲不會有功能的開銷,而且我我想知道是否應該在我的程序中使用這種方法來提高性能。所以我的問題是:

我應該用#define替換所有我的函數來提高我的代碼的性能嗎?

+0

請使用尾部而不是前導下劃線:大多數前導下劃線的使用違反了ISO C標準,下劃線後跟大寫字母尤其糟糕,因爲這就是新的C語言關鍵字所使用的('_Bool','' _Complex','_Generic','_Atomic',...) – Christoph

回答

8

不可以。根據感知的性能差異,您不應該在宏和函數之間作出決定。你應該根據宏函數的優點對它進行評估。一般選擇功能。

宏有很多隱藏的缺點,可以咬你。例如,您在這裏轉換爲宏是不正確的(或者至少不保留原始函數的語義)。宏distance的參數得到兩次評估。想象一下,我做以下調用

distance(GetPointA(), GetPointB()); 

在宏版本實際上導致4函數調用,因爲每個參數計算兩次。如果保留distance作爲函數,它只會導致3個函數調用(距離和每個參數)。注意:我忽略了上述計算中sqrtpow的影響,因爲它們在兩個版本中都是相同的。

3

有三件事情:

  • 正常功能,如您distance上述
  • 內聯函數
  • 預處理宏

雖然功能保證某種類型的安全,他們也招致由於在每次函數調用時都需要使用堆棧幀,因此性能會有所下降。來自內聯函數的代碼在呼叫站點被複制,因此不會支付懲罰 - 但是,您的代碼大小將會增加。宏不提供類型安全性,也涉及文本替換。

從三者中選擇,我通常會使用內聯函數。宏只有當它們非常短並且非常有用這種形式時(例如來自Linux內核的hlist_for_each

3

我推薦使用inline函數而不是宏。它會給你任何可能的宏觀性能好處,沒有醜陋。 (宏有一些陷阱,使得它們非常不適合作爲函數的一般替代品,特別是,每次使用宏時,都會評估宏參數,而函數參數在「調用」之前每次評估一次。)

inline float distance(CPoint p1, CPoint p2) 
{ 
    float dx = p2.x - p1.x; 
    float dy = p2.y - p1.y; 
    return sqrt(dx*dx + dy*dy); 
} 

(注意我也換成pow(dx, 2)dx * dx。這兩個是等價的,和乘法是更可能是有效的。一些編譯器可能會試圖優化掉調用pow ......但想他們替換一下它與。)

1

如果使用一個相當成熟的編譯器它propaby會在彙編級別爲您做這個,如果優化打開。

對於gcc的-O3或(對於「小」功能),即使-O2選項也會這樣做。

有關詳細信息,您可能需要考慮http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html針對「-finline *」選項。

3

Jared的權利,並且在這種特定情況下,在pow調用和sqrt調用中花費的週期將比在調用distance時花費的週期多2個數量級的範圍。

有時人們會認爲小碼等於小時間。並非如此。