2011-03-31 63 views
0

我正經歷着在工作中的一些代碼,我發現這個這是功能保證內聯擴展

inline 
    FLAGS get_flags(void) { 
    FLAGS res; 
    memset(&res, 0, sizeof(res)); 
    return res 
} 

在包括程序中的頭文件此聲明。我意識到如果它沒有被內聯,將會是一件非常糟糕的事情,因爲它被分配在堆棧上。我們從來沒有遇到過有關代碼的問題,但我只是好奇而已。

+2

該函數是否內聯與函數的安全性無關 - 您將按值返回值。 – Jon 2011-03-31 18:50:03

+0

重要嗎?對memset()的調用肯定不會內聯,因此內聯函數不會節省太多。 – Clifford 2011-03-31 19:12:53

+0

@Clifford:實際上,我很確定gcc用-O3和可能的MSVC對它進行了內聯。 – GManNickG 2011-03-31 19:19:00

回答

6

不,不保證內聯擴展。 inline僅僅是編譯器的提示。

也就是說,儘管res確實存在於堆棧中,但您的返回它的副本。如果內聯擴展沒有發生,它不會是「非常糟糕的事情」。

+0

關於副本的好處...不知道爲什麼我沒有看到... :)謝謝 – DavidMFrey 2011-03-31 18:48:23

2

不,它不能保證編譯器將內聯它。見this answer

正如Strousoup說,在C++編程語言

的聯說明是一個提示,它應該嘗試生成代碼[...]內聯,而不是放下了代號爲函數一次編譯然後通過通常的函數調用機制進行調用。

請注意關鍵詞提示

0

編譯器被允許忽略inline關鍵字。如果它是一個非常糟糕的事情不inline這一點,那麼你應該使用#define宏,或使一類具有適當的構造函數(因爲你已經標記這是C++)等

1

inline有兩個目的,但只有一個問題了。

正如其他人所說,暗示該函數應該內聯編譯器的目的幾乎是無用的。編譯器比編程器更好地確定應該內聯的內容。

但是,重要的第二次使用(其中在您的情況下適用)是它打破了單定義規則(ODR)。也就是說,在正常情況下,鏈接器不能接受看到多次定義的符號。但是,如果該符號被宣佈爲inline,則可以自由地假定每個符號的定義相同並忽略其餘符號。

因爲你的函數是一個頭文件,它可能會在一個以上的轉換單元中定義,所以你需要打破ODR,讓你的代碼沒有錯誤編譯。

+0

[Include guard](http://en.wikipedia.org/wiki/Include_guard)應該用於在任何情況下都不允許在*翻譯單元*中進行多重定義,如果使用,那麼在這種情況下,'inline'與'static'具有相同的效果。 – Clifford 2011-04-01 19:11:37

+0

@Clifford:這是部分正確的。包括警衛會按你所說的行事,但他們不會保護你免受多個翻譯單位的任何傷害。然而,'inline'與'static' int hat不一樣,因爲'inline'允許鏈接器合併定義,'static'不能。 – GManNickG 2011-04-01 19:23:59

+0

@GMan:我的觀點是你最初說的是「在* a *翻譯單位」而不是*多個*翻譯單位。靜態和內聯接受的公平點之間的差異,但是鏈接器是否執行該優化再次不能保證,鏈接器將不得不看到編譯器生成的代碼是相同的,如果多於一個內聯具有相同的名稱被定義,或者每個對象模塊被編譯爲不同的選項。 – Clifford 2011-04-02 07:57:09

0

關於「在棧上分配」變量函數的行爲不會改變,不管它是內聯與否。因此,無論與堆棧相關的問題如何,它們在任何一種情況下都同樣有效(或無效)。

0

大多數編譯器唯一真正的在線時,如果在所有優化接通。通常情況下,您可以關閉優化以使用源代碼級調試器進行調試,而且通常這些調試器對於內聯代碼的表現不佳,從而使其調試更加困難。如果函數正常實現,調試器不需要考慮內聯。