2017-09-27 243 views
6

這或多或少澄清 Casting a function pointer to another type與示例代碼的請求優化了輔助功能

struct my_struct; 
void my_callback_function(struct my_struct* arg); 
void do_stuff(void (*cb)(void*)); 

static void my_callback_helper(void* pv) 
{ 
    my_callback_function(pv); 
} 
int main() 
{ 
    do_stuff(&my_callback_helper); 
} 

回答說,「好」的編譯器應該能夠優化出 的my_callback_helper()功能,但我發現沒有編譯器在https://gcc.godbolt.org ,做它和輔助功能被一直產生,即使它just a jump to my_callback_function()(-O3):

my_callback_helper: 
     jmp  my_callback_function 
main: 
     subq $8, %rsp 
     movl $my_callback_helper, %edi 
     call do_stuff 
     xorl %eax, %eax 
     addq $8, %rsp 
     ret 

所以我的問題是:標準中有什麼能夠防止編譯器消除幫助者?

+0

以我的經驗,編譯器傾向於在即使在編譯時確定的函數指針的值內聯函數指針調用做的不好。你可以試着折騰'inline'關鍵字。據我所知,標準中沒有任何內容阻止優化。 – Lundin

回答

3

標準中沒有任何東西可以直接阻止這種優化。但在實踐中,編譯器並不總是可能的,因爲他們沒有「全貌」。

您已經採取的my_callback_helper地址。所以編譯器不能輕易優化它,因爲它不知道do_stuff如何處理它。在定義了do_stuff的單獨模塊中,編譯器不知道它可以簡單地使用/調用my_callback_function來代替它的參數(my_callback_helper)。爲了完全優化出my_callback_helper,編譯器必須知道do_stuff的功能。但是do_stuff是一個外部函數,其定義不適用於編譯器。因此,如果您提供do_stuff及其所有用途的定義,則可能會發生此類優化。

+1

這也應該在編譯和「鏈接」步驟中使用鏈接時間優化(-flto和GCC)來重新使用。 – dbrank0

+0

我想也許這是禁止的,因爲可能性指針比較。 'do_stuff()'可能試圖將接收到的指針與'my_callback_function()'進行比較。通過優化,比較將會說'my_callback_function == my_callback_helper',並且兩個不同的對象具有相同的地址可能是不合法的。如果它是非法的,那麼它有點不幸跳躍不能被消除。也許這對於fn-casts來說更好是實現定義的而不是未定義的。 – PSkocik