又是乙個面試容易被問到的東西 C 內聯

2021-07-10 15:04:25 字數 3444 閱讀 5001

突然看到c++primer中講到,對於vector的乙個迴圈,呼叫語句:(示例**i=v.begin()不是很規範,雖然不會出錯,客官請將就著看)

[cpp]view plain

copy

print

? for (int i=v.begin() ; i  

for (int i=v.begin() ; i

1、inline的引出

考慮下列min()函式(例子來自c++primer第三版303頁)

[cpp]view plain

copy

print

? int min( int v1, int v2 )    

int min( int v1, int v2 )

為這樣的小操作定義乙個函式的好處是:

a.如果一段**包含min()的呼叫,那閱讀這樣的**並解釋其含義比讀乙個條件操作符的例項,可讀性會強很多。

b.改變乙個區域性化的實現比更改乙個應用中的300個出現要容易得多

c.語義是統一的,每個測試都能保證相同的方式實現

d.函式可以被重用,不必為其他的應用重寫**

不過,將min()寫成函式有乙個嚴重的缺點:呼叫函式比直接計算條件操作符要慢很多。那怎麼能兼顧以上優點和效率呢?c++提供的解決方案為inline(內聯)函式

2、inline的原理:**替代

在程式編譯時,編譯器將程式中出現的內聯函式的呼叫表示式用內聯函式的函式體來進行替代。

例如,如果乙個函式被指定為inline 函式則它將在程式中每個呼叫點上被內聯地展開例如

[cpp]view plain

copy

print

? int minval2 = min( i, j );  

int minval2 = min( i, j );
在編譯時被展開為

[cpp]view plain

copy

print

? int minval2 = i < j << i : j;  

int minval2 = i < j << i : j;
則把min()寫成函式的額外執行開銷從而被消除了。

3、inline的使用

讓乙個函式成為內聯函式,隱式的為在類裡定義函式,顯式的則是在函式前加上inline關鍵字說明。

4、使用inline的一些注意事項

a.從inline的原理,我們可以看出,inline的原理,是用空間換取時間的做法,是以**膨脹(複製)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率。如果執行函式體內**的時間,相比於函式呼叫的開銷較大,那麼效率的收穫會很少。所以,如果函式體**過長或者函式體重有迴圈語句,if語句或switch語句或遞迴時,不宜用內聯

b.關鍵字inline 必須與函式定義體放在一起才能使函式成為內聯,僅將inline 放在函式宣告前面不起任何作用。內聯函式呼叫前必須宣告。《高質量c/c++程式設計》裡乙個例子。

[cpp]view plain

copy

print

? inline

void foo(int x, int y); // inline 僅與函式宣告放在一起

void foo(int x, int y)    

inline void foo(int x, int y); // inline 僅與函式宣告放在一起

void foo(int x, int y)

以上**不能成為內聯函式,而以下則可以

[cpp]view plain

copy

print

? void foo(int x, int y);  

inline

void foo(int x, int y) // inline 與函式定義體放在一起  

void foo(int x, int y);

inline void foo(int x, int y) // inline 與函式定義體放在一起

所以說,inline 是一種「用於實現的關鍵字」,而不是一種「用於宣告的關鍵字」。對於以上例子,林銳還建議,只在定義前加上inline,而不是在宣告和定義前都加,因為這能體現高質量c++/c 程式設計風格的乙個基本原則:宣告與定義不可混為一談。

c.inline對於編譯器來說只是乙個建議,編譯器可以選擇忽略該建議。換句話說,哪怕真的寫成了inline,也沒有任何錯誤的情況下,編譯器會自動進行優化。所以當inline中出現了遞迴,迴圈,或過多**時,編譯器自動無視inline宣告,同樣作為普通函式呼叫。

總結下:

樓主覺得可以將內聯理解為c++中對於函式專有的巨集,對於c的函式巨集的一種改進。對於常量巨集,c++提供const替代;而對於函式巨集,c++提供的方案則是inline。在c中,大家都知道巨集的優勢,編譯器通過複製巨集**的方式,省去了引數壓棧,生成彙編的call呼叫,返回引數等操作,雖然存在一些安全隱患,但在效率上,還是很可取的。

不過函式巨集還是有不少缺陷的,主要有以下:

a.在複製**時,容易出現一想不到的邊際效應,比如經典的

[cpp]view plain

copy

print

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

#define max(a, b) (a) > (b) ? (a) : (b)
在執行語句:

[cpp]view plain

copy

print

? result = max(i, j) + 2 ;  

result = max(i, j) + 2 ;
時,會被解釋為

[cpp]view plain

copy

print

? result = (i) > (j) ? (i) : (j) + 2 ;  

result = (i) > (j) ? (i) : (j) + 2 ;
b.使用巨集,無法進行除錯,雖然windows提供了assert巨集

c.使用巨集,無法訪問類的私有成員

所以,c++ 通過內聯機制,既具備巨集**的效率,又增加了安全性,還可以自由操作類的資料成員,算是乙個比較完美的解決方案。

關於巨集,大家還可以參考下:更原創,內容豐富,可取,總結了各家觀點,稍微整理了下,不過還是蠻清楚的。

就這樣吧,菜鳥goes on ~~~

關於 的乙個容易被忽略的問題

a 0,1,2,3,0,1,2 5 a 4 3 在一般來說,所有的使用者都知道元組一旦被建立就不可更改,除非用乙個新的元組來覆蓋它,但是上面的示例有了不同的反饋。執行之後得到了異常 typeerror tuple object does not support item assignment 在這個...

又是乙個忙碌的週末

又度過了乙個繁忙的週末,幾乎每個週末都要因為實習的筆試跑一趟廣州 先說說銀行業從業考試,說實在的最開始報名也並沒有想好為什麼要考,只是為了在投相關公司的時候能說明自己專業不相關但是對於業務有了解吧 我並沒有把考試的輔導書看完 沒買,圖書館借的 然後就是做題 在考試大 上的免費模擬試題 但是實際考試的...

又是乙個新的站點

在這之前一直是在自學gis,在帶著工作壓力之下自學了乙個月。我發現此時的學習真的是不如在學校的景靜和心靜。也或許是對於這職業生涯的起點多多少少帶有的緊張心情。但越是這樣就越要掌握好自己的思緒,不要急於求成。當你面對乙個你完全陌生的東西,不知從何下手時,你就看見什麼,你就研究什麼吧。在順著這條專研的路...