常用提高C 效率的方法

2021-10-02 18:55:44 字數 4096 閱讀 9300

自從七十年代c語言誕生以來,一直以其靈活性、高效率和可移植性為軟體開發人員所鍾愛,成為系統軟體開發的首選工具。而c++作為c語言的繼承和發展,不僅保留了c語言的高度靈活、高效率和易於理解等諸多優點,還包含了幾乎所有物件導向的特徵,成為新一代軟體系統構建的利器。

相對來說,c語言是一種簡潔的語言,所涉及的概念和元素比較少,主要是:巨集(macro)、指標(pointer)、結構(struct)、函式(function)和陣列(array),比較容易掌握和理解。而c++不僅包含了上面所提到的元素,還提供了私有成員(private members)、公有成員(public members)、函式過載(function overloading)、預設引數(default parameters)、建構函式、析構函式、物件的引用(references)、操作符過載(operator overloading)、友元(friends)、模板(templates)、異常處理(exceptions)等諸多的要素,給程式設計師提供了更大的設計空間,同時也增加了軟體設計的難度。

c語言之所以能被廣泛的應用,其高效率是乙個不可忽略的原因,c語言的效率能達到組合語言的80%以上,對於一種高階語言來說,c語言的高效率就不言而喻了。那麼,c++相對於c來說,其效率如何呢?實際上,c++的設計者stroustrup要求c++效率必須至少維持在與c相差5%以內,所以,經過精心設計和實現的c++同樣有很高的效率,但並非所有c++程式具有當然的高效率,由於c++的特殊性,一些不好的設計和實現習慣依然會對系統的效率造成較大的影響。同時,也由於有一部分程式設計師對c++的一些底層實現機制不夠了解,就不能從原理上理解如何提高軟體系統的效率。

本文主要討論兩個方面的問題:第一,對比c++的函式呼叫和c函式呼叫,解析c++的函式呼叫機制;第二,例舉一些c++程式設計師不太注意的技術細節,解釋如何提高c++的效率。為方便起見,本文的討論以下面所描述的單一繼承為例(多重繼承有其特殊性,另作討論)。  

class x

; //內聯函式

void normalfunc(); //普通成員函式

static void staticfunc(); //靜態函式

private:

int m_imember;

};class xx: public x

;c++的的函式分為四種:內聯函式(inline member function)、靜態成員函式(static member function)、虛函式(virtual member function)和普通成員函式。

內聯函式類似於c語言中的巨集定義函式呼叫,c++編譯器將內聯函式的函式體擴充套件在函式呼叫的位置,使內聯函式看起來象函式,卻不需要承受函式呼叫的開銷,對於一些函式體比較簡單的內聯函式來說,可以大大提高內聯函式的呼叫效率。但內聯函式並非沒有代價,如果內聯函式體比較大,內聯函式的擴充套件將大大增加目標檔案和可執行檔案的大小;另外,inline關鍵字對編譯器只是一種提示,並非乙個強制指令,也就是說,編譯器可能會忽略某些inline關鍵字,如果被忽略,內聯函式將被當作普通的函式呼叫,編譯器一般會忽略一些複雜的內聯函式,如函式體中有複雜語句,包括迴圈語句、遞迴呼叫等。所以,內聯函式的函式體定義要簡單,否則在效率上會得不償失。

靜態函式的呼叫,如下面的幾種方式:  

x obj; x* ptr = &obj;

obj.staticfunc();

ptr->staticfunc();

x::staticfunc();  

將被編譯器轉化為一般的c函式呼叫形式,如同這樣: mangled_name_of_x_staticfunc();

mangled_name_of_x_staticfunc();

// ptr- >staticfunc();

mangled_name_of_x_staticfunc();

// x::staticfunc();  

mangled_name_of_x_staticfunc()是指編譯器將x::staticfunc()函式經過變形(mangled)後的內部名稱(c++編譯器保證每個函式將被mangled為獨一無二的名稱,不同的編譯器有不同的演算法,c++標準並沒有規定統一的演算法,所以mangled之後的名稱也可能不同)。可以看出,靜態函式的呼叫同普通的c函式呼叫有完全相同的效率,並沒有額外的開銷。

普通成員函式的呼叫,如下列方式:  

x obj; x* ptr = &obj;

obj.normalfunc();

ptr->normalfunc();  

將被被編譯器轉化為如下的c函式呼叫形式,如同這樣。 mangled_name_of_x_normalfunc(&obj);

mangled_name_of_x_normalfunc(ptr);

// ptr- >normalfunc();  

www.zztarena.com  

可以看出普通成員函式的呼叫同普通的c呼叫沒有大的區別,效率與靜態函式也相同。編譯器將重新改寫函式的定義,增加乙個const x* this引數將呼叫物件的位址傳送進函式。

虛函式的呼叫稍微複雜一些,為了支援多型性,實現執行時刻繫結,編譯器需要在每個物件上增加乙個欄位也就是vptr以指向類的虛函式表vtbl。

虛函式的多型性只能通過物件指標或物件的引用呼叫來實現,如下的呼叫:  

x obj;

x* ptr = &obj; x& ref = obj;

ptr->virtualfunc();

ref.virtualfunc();  

將被c++編譯器轉換為如下的形式。  

( *ptr->vptr[2] )(ptr);

( *ptr->vptr[2] )(&ref);  

其中的2表示virtualfunc在類虛函式表的第2個槽位。可以看出,虛函式的呼叫相當於乙個c的函式指標呼叫,其效率也並未降低。

由以上的四個例子可以看出,c++的函式呼叫效率依然很高。但c++還是有其特殊性,為了保證物件導向語義的正確性,c++編譯器會在程式設計師所編寫的程式基礎上,做大量的擴充套件,如果程式設計師不了解編譯器背後所做的這些工作,就可能寫出效率不高的程式。對於一些繼承層次很深的派生類或在成員變數中包含了很多其它類物件(如xx中的m_strname變數)的類來說,物件的建立和銷毀的開銷是相當大的,比如xx類的預設建構函式,即使程式設計師沒有定義任何語句,編譯器依然會給其建構函式擴充以下**來保證物件語義的正確性:  

xx::xx()

;所以為了提高效率,減少不必要的臨時物件的產生、拖延暫時不必要的物件定義、用初始化代替賦值、使用建構函式初始化列表代替在建構函式中賦值等方法都能有效提高程式的執行效率。以下舉例說明:

1、 減少臨時物件的生成。如以傳送物件引用的方式代替傳值方式來定義函式的引數,如下例所示,傳值方式將導致乙個xx臨時物件的產生  

效率不高的做法 高效率做法

void function( xx xx ) void function( const xx& xx )

}  2、 拖延暫時不必要的物件定義。在c中要將所有的區域性變數定義在函式體頭部,考慮到c++中物件建立的開銷,這不是乙個好習慣。如下例,如果大部分情況下bcache為"真",則拖延xx的定義可以大大提高函式的效率。 效率不高的做法高效率做法

void function( bool bcache )void function( bool bcache )

return;  

}//對xx進行操作xx xx;

//對xx進行操作

…return;return;

}}  

3、 可能情況下,以初始化代替先定義後賦值。如下例,高效率的做法會比效率不高的做法省去了cache變數的預設構造函式呼叫開銷。 效率不高的做法高效率做法

void function( const xx& xx )void function( const xx& xx )

}  4、 在建構函式中使用成員變數的初始化列表代替在建構函式中賦值。如下例,在效率不高的做法中,xx的建構函式會首先呼叫m_strname的預設建構函式,再產生乙個臨時的string object,用空串""初始化臨時物件,再以臨時物件賦值(assign)給m_strname,然後銷毀臨時物件。而高效的做法只需要呼叫一次m_strname的建構函式。 效率不高的做法高效率做法

xx::xx()xx::xx() : m_strname( "" )

}  類似的例子還很多,如何寫出高效的c++程式需要實踐和積累,但理解c++的底層執行機制是乙個不可缺少的步驟,只要平時多學習和思考,編寫高效的c++程式是完全可行的。

C 效率提高

最近作了個解析log的小工具。做出來後,速度有點慢。就優化了一下,經驗總結如下。編譯環境是 vs2003 1,把類的成員函式內的函式作用域變數 object 變成 類的成員變數。函式內的變數,其生存週期是函式體。因此,函式每次被呼叫時,都要為其分配記憶體空間,結束時 記憶體空間。在這次開發中,類物件...

如何提高C 效率

分類 c c 2012 02 25 16 43 1023人閱讀收藏 舉報c 編譯器function overloading語言c 自從七十年代c語言誕生以來,一直以其靈活性 高效率和可移植性為軟體開發人員所鍾愛,成為系統軟體開發的首選工具。而c 作為c語言的繼承和發展,不僅保留了c語言的高度靈活 高...

提高SQL執行效率的方法

oracle提供了多種方法用於減少花在剖析oracle sql表示式上的時間,在執行帶有大量執行計畫的複雜查詢時剖析過程會拖累系統的效能。現在我們來簡要地看看這些方法中的幾種。1 使用ordered提示 oracle必須花費大量的時間來剖析多 的合併,用以確定 合併的最佳順序。如果sql表示式涉及七...