函數調用的開銷

原文地址:http://blog.csdn.net/gohome520/article/details/6328762


做了幾個實驗,簡單學習瞭解一下函數調用的開銷。

 

程序1—沒有參數的函數調用:

  1. #include <stdio.h>  
  2. void test()  
  3. {  
  4.     return;  
  5. }  
  6. int main(int argc, char *argv[])  
  7. {  
  8.     test();  
  9.     return 0;  
  10. }  
 

用gcc -S得到程序1的彙編代碼:

  1.         .file   "test.c"  
  2.         .text  
  3. .globl test  
  4.         .type   test, @function  
  5. test:  
  6.         pushl   %ebp  
  7.         movl    %esp, %ebp  
  8.         nop  
  9.         popl    %ebp  
  10.         ret  
  11.         .size   test, .-test  
  12. .globl main  
  13.         .type   main, @function  
  14. main:  
  15.         pushl   %ebp  
  16.         movl    %esp, %ebp  
  17.         call    test  
  18.         movl    $0, %eax  
  19.         popl    %ebp  
  20.         ret  
  21.         .size   main, .-main  
  22.         .ident  "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"  
  23.         .section        .note.GNU-stack,"",@progbits  
 

從上面彙編代碼可以看出,對於沒有參數函數調用的開銷:

1. 調用函數和返回,所以需要執行一次call/ret指令對。

2. 函數內部,需要保護現場,所以需要把%ebp push到棧中,返回前,再pop出來。

3. 構造函數運行環境,將%ebp賦值爲當前的棧頂%esp。

則沒有參數函數調用開銷是5個指令。

 

 

程序2-帶參數函數調用:

  1. #include <stdio.h>  
  2. void test(int a)  
  3. {  
  4.         (a)++;  
  5.         return;  
  6. }  
  7. int main(int argc, char *argv[])  
  8. {  
  9.         int a = 1;  
  10.         test(a);  
  11.         return 0;  
  12. }  
 

用gcc -S得到程序2的彙編代碼:

  1.         .file   "test.c"  
  2.         .text  
  3. .globl test  
  4.         .type   test, @function  
  5. test:  
  6.         pushl   %ebp  
  7.         movl    %esp, %ebp  
  8.         addl    $1, 8(%ebp)  
  9.         nop  
  10.         popl    %ebp  
  11.         ret  
  12.         .size   test, .-test  
  13. .globl main  
  14.         .type   main, @function  
  15. main:  
  16.         pushl   %ebp  
  17.         movl    %esp, %ebp  
  18.         subl    $20, %esp  
  19.         movl    $1, -4(%ebp)  
  20.         movl    -4(%ebp), %eax  
  21.         movl    %eax, (%esp)  
  22.         call    test  
  23.         movl    $0, %eax  
  24.         leave  
  25.         ret  
  26.         .size   main, .-main  
  27.         .ident  "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"  
  28.         .section        .note.GNU-stack,"",@progbits  
 

 

相比於沒有參數函數調用的開銷,帶參數函數調用多2個指令,用於傳遞參數:

movl -4(%ebp), %eax

movl %eax, (%ebp)

每個參數的傳遞時都需要2個指令。

而如果是指針參數,則函數在使用時,還得需要2個指令。

 

 

這麼看,函數調用的開銷還挺大的。

所以,當一個函數很小且調用頻繁時,應該用宏或內聯函數進行替代。

 

另外,雖然函數調用有開銷,但除非有特殊的必要,該用函數的地方還是應該使用函數,否則會嚴重降低代碼的可讀性和可維護性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章