2010-06-02 196 views
2

我知道我可以傳遞一個函數指針作爲模板參數,並得到調用它內聯,但我想,如果這幾天內聯一個「明顯的」內聯能夠函數像任何編譯器:C++函數指針內聯

inline static void Print() 
{ 
std::cout << "Hello\n"; 
} 

.... 

void (*func)() = Print; 

func(); 

在Visual Studio 2008下,它足夠聰明,可以直接調用指令,所以它似乎是一種恥辱,它不能再走一步嗎?

+0

你確定這不是對'ostream <<'的直接調用指令嗎? – James 2010-06-02 16:19:56

+0

請使用編輯器中的「101010」按鈕格式化您的代碼。 – sbi 2010-06-02 16:22:21

+0

是的,我檢查了大會。在代碼格式我不知道,但現在我:) – iam 2010-06-02 16:38:44

回答

2

GNU的G ++開始在優化級別-O1

main: 
    subq $8, %rsp 
    movl $6, %edx 
    movl $.LC0, %esi 
    movl $_ZSt4cout, %edi 
    call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_E 
    movl $0, %eax 
    addq $8, %rsp 
    ret 

其中.LC0是.string 「你好\ N」 4.5內聯對我來說。

比較,沒有優化,G ++ -O0,它沒有內聯:GCC的

main: 
    pushq %rbp 
    movq %rsp, %rbp 
    subq $16, %rsp 
    movq $_ZL5Printv, -8(%rbp) 
    movq -8(%rbp), %rax 
    call *%rax 
    movl $0, %eax 
    leave 
    ret 
+0

偉大的這是很好的知道,因爲有各種有用的構造,這將使他們的使用零性能影響:) 一個恥辱,Visual C++不是很聰明! 謝謝。 – iam 2010-06-03 03:49:36

1

那麼編譯器並不真正知道該變量是否會被覆蓋到某處(可能在另一個線程中?),所以它在謹慎的方面發生了錯誤,並將其作爲函數調用來實現。

我剛剛在版本構建中檢查了VS2010,它沒有被內聯。

順便說一句,你裝飾功能inline是沒用的。該標準說如果你得到一個函數的地址,任何inline提示都將被忽略。

編輯:但請注意,雖然你的函數沒有被內聯,但變量IS不見了。在反彙編中,call使用直接地址,它不會將該變量加載到寄存器中並調用該地址。

+1

是的,這是什麼我以爲我只是試着__restrict,而且const也無濟於事。是的,我嘗試內聯和__forceinline,因爲你永遠不知道:) IE:void(* const __restrict func)()= Local :: Print; 我希望在VS2010中,他們可能會因爲lambda等原因而產生 - 是否__restrict改變了VS2010的局面? 謝謝 – iam 2010-06-02 16:37:55

+0

不,編譯器拒絕內聯,這有點奇怪,因爲如果它消除了變量,那麼變量就沒有變化的危險,所以它可以用函數體來代替'call'。呵呵.. – Blindy 2010-06-02 16:43:03

+0

編譯器不必假定變量可以在另一個線程中被覆蓋。如果有可能同一個線程可能會覆蓋變量,編譯器必須保證它的安全,但是在OP所示的簡單情況下,不存在這種風險(這也是爲什麼它能夠消除變量)。編譯器*應該*能夠內聯這樣一個簡單的例子。 – jalf 2010-06-02 18:06:57

2

新版本(4.4以上版本)有一個選項名爲-findirect,內聯。如果GCC能證明自己的函數指針是常量,那麼它會直接調用函數或完全內聯函數。