2013-07-28 108 views
1

在考察下面的功能的拆卸,C/C++編譯器可以內聯malloc()內聯函數嗎?

void * malloc_float_align(size_t n, unsigned int a, float *& dizi) 
    { 
     void * adres=NULL; 
     void * adres2=NULL; 
     adres=malloc(n*sizeof(float)+a); 
     size_t adr=(size_t)adres; 
     size_t adr2=adr+a-(adr&(a-1u)); 
     adres2=(void *) adr2; 
     dizi=(float *)adres2; 
     return adres; 
    } 

內置函數甚至不與inline優化標誌集內聯。

; Line 26 
$LN4: 
    push rbx 
    sub rsp, 32     ; 00000020H 
; Line 29 
    mov ecx, 160    ; 000000a0H 
    mov rbx, r8 
    call QWORD PTR __imp_malloc <------this is not inlined 
; Line 31 
    mov rcx, rax 
; Line 33 
    mov rdx, rax 
    and ecx, 31 
    sub rdx, rcx 
    add rdx, 32     ; 00000020H 
    mov QWORD PTR [rbx], rdx 
; Line 35 
    add rsp, 32     ; 00000020H 
    pop rbx 
    ret 0 

問:這是一個必須具備的功能特性就像malloc?我們可以通過某種方式來檢查它(或者像strcmp/new/free/delete之類的其他函數)嗎?這是禁止的嗎?

+0

被誰禁止?該標準不涉及這些實施細節。 – delnan

+0

由編譯器。我怎樣才能讓他們內聯? –

+0

如果只有一個調用者,或者被調用函數的複雜度小於調用本身的複雜度,則內聯是最有益的。 'malloc'幾乎與這個尺度的兩端相反。 – MSalters

回答

2

通常,所述編譯器將內聯函數時,它具有在編譯期間可用的源代碼(換言之,該函數被定義,而不是僅僅一個原型說明)在頭文件中)。

但是,在這種情況下,函數(malloc)位於DLL中,因此源代碼在編譯代碼期間無法用於編譯器。它與malloc沒有關係(等等)。然而,malloc也可能不會被內聯,因爲它是一個相當大的函數[至少經常是],即使源代碼可用,它也不能被內聯。

如果您正在使用Visual Studio,你可以幾乎肯定找到適合您的運行時庫的源代碼,因爲它是與Visual Studio封裝。因爲系統中的許多不同程序都使用相同的函數,因此將它們放入一個爲所有功能的「用戶」加載一次的DLL中將會很好地節省儘管malloc可能只有幾百字節,但像printf這樣的函數可以很容易地爲可執行文件的大小增加5-25KB,乘以printf的「用戶」數量和有可能是幾百千字節剛剛從一個功能「節省」 - 當然,所有其他功能,如fopenfclosemalloccallocfree,等所有每加一點點的整體尺寸)

+0

好的,我有使用malloc的函數包的dll。我怎樣才能打開DLL看到的成分?例如:第135行:malloc_starts_here,第1040行:END malloc –

+0

如果您使用調試器[並且您已啓用調試符號]將其單個設置爲它,則它應該爲您提供源代碼。 –

1

C編譯器允許內聯malloc(或者,如您在示例中看到的那樣,它的一部分),但不需要需要來內聯任何東西。它使用的啓發式方法不需要記錄,它們通常非常複雜,但通常只有簡短的函數會被內聯,因爲否則可能會導致代碼膨脹。

1

malloc和朋友在運行時庫中實現,所以他們沒有可用的內聯。他們需要在他們的頭文件中實現它們,以實現這一點。

如果你想看到他們的拆裝,你可以走進他們與調試。或者,根據您使用的編譯器和運行時,源代碼可能是可用的。例如,它可用於gcc和msvc。

1

最主要停止malloc()等人的內聯是其複雜性 - 而這是提供的功能沒有內嵌定義一個明顯的事實。此外,您可能需要不同版本的功能在不同的時間;對於像valgrind這樣的工具來說工作起來會更困難(更麻煩),並且如果他們的代碼以內聯方式展開,則無法安排使用調試版本的功能。