C++中哪些函數不能聲明爲inline?

inline關鍵字僅僅是對編譯器的建議,編譯器有權力決定一個函數是否在調用處嵌入。由於內聯函數要在調用處展開,編譯器必須能在每個調用處能看到該函數的定義,所以最好將函數實現放在頭文件中(並且實如今類定義中的成員函數即使不加inline關鍵字也會自動成爲內聯函數)。在實現文件中該函數以前要加上inline關鍵字的方式是有問題的:若是調用的obj文件在函數定義以前生成,那麼該處就沒法嵌入內聯函數了。若是普通函數須要成爲內聯函數,在定義時加上inline關鍵字。 c++

  1. 包含了遞歸、循環等結構的函數通常不會被內聯。
  2. 虛擬函數通常不會內聯,可是若是編譯器能在編譯時肯定具體的調用函數,那麼仍然會就地展開該函數。
  3. 若是經過函數指針調用內聯函數,那麼該函數將不會內聯而是經過call進行調用。
  4. 構造和析構函數通常會生成大量代碼,所以通常也不適合內聯。
  5. 若是內聯函數調用了其餘函數也不會被內聯。

若是想要阻止某函數被內聯,能夠在函數體前加上 __attribute__((noinline)) 。 函數

   

有時函數是否原地展開與編譯時指定的優先級有關,下面就是一個例子: 優化

inline int foo(int x) { spa

return x+42; 命令行

} 指針

   

int main(int argc, char* argv[]) c++11

{ 遞歸

printf("%d\n", foo(42)); 編譯器

 

return 0; string

}

   

使用以下命令行獲得彙編代碼,g++ -S -Wall -DDEBUG -D_GNU_SOURCE -std=c++11 -I/usr/include test.cpp:

   

.section        .text._Z3fooi,"axG",@progbits,_Z3fooi,comdat

.weak        _Z3fooi

.type        _Z3fooi, @function

_Z3fooi:

//rbp寄存器的值入棧,保存main函數的棧基地址

pushq        %rbp

//rsp寄存器的值寫入到rbp寄存器,將main函數的棧頂指針賦予foo函數的棧底指針

movq        %rsp, %rbp

//此時edi寄存器中的值是42,放入foo棧底向上4byte

movl        %edi, -4(%rbp)

//42放入eax寄存器

movl        -4(%rbp), %eax

//當即數21eax寄存器中的值(42)相加

addl        $21, %eax

//恢復main函數的棧底

popq        %rbp

//返回

ret

.size        _Z3fooi, .-_Z3fooi

.section        .rodata

.LC0:        

.string        "%d\n"

.text

.globl        main

.type        main, @function

main:

//rbp寄存器的值入棧,保存_start函數的棧基地址

pushq        %rbp

//rsp寄存器的值寫入到rbp寄存器,將_start函數的棧頂指針賦予main函數的棧底指針

movq        %rsp, %rbp

//rsp寄存器的值減去當即數16,即main函數的棧大小爲16

subq        $16, %rsp

//edi寄存器中的值放入rbp寄存器中的值減4的位置(棧底向上4byte

movl        %edi, -4(%rbp)

//rsi寄存器中的值放入rbp寄存器中的值減16的位置(棧底向上16byte

movq        %rsi, -16(%rbp)

//當即數42放入edi寄存器

movl        $42, %edi

//調用函數foo

call        _Z3fooi

//eax寄存器的值(63)放入esi寄存器

movl        %eax, %esi

//LC0段地址放入edi寄存器

movl        $.LC0, %edi

movl        $0, %eax

call        printf

movl        $0, %eax

leave

ret

.size        main, .-main

   

使用以下命令行生成彙編代碼:g++ -S -O -Wall -DDEBUG -D_GNU_SOURCE -std=c++11 -I/usr/include test.cpp(增長了一個優化選項)

.section        .rodata.str1.1,"aMS",@progbits,1

.LC0:

.string        "%d\n"

.globl        main

.type        main, @function

main:

subq        $8, %rsp

movl        $63, %esi

movl        $.LC0, %edi

call        printf

movl        $0, %eax

addq        $8, %rsp

ret

.size        main, .-main

可見foo函數並未被調用,而是直接將當即數63放入esi寄存器做爲printf函數的參數。

相關文章
相關標籤/搜索