原文地址:http://blog.csdn.net/gohome520/article/details/6328762
做了幾個實驗,簡單學習瞭解一下函數調用的開銷。
程序1—沒有參數的函數調用:
- #include <stdio.h>
- void test()
- {
- return;
- }
- int main(int argc, char *argv[])
- {
- test();
- return 0;
- }
用gcc -S得到程序1的彙編代碼:
- .file "test.c"
- .text
- .globl test
- .type test, @function
- test:
- pushl %ebp
- movl %esp, %ebp
- nop
- popl %ebp
- ret
- .size test, .-test
- .globl main
- .type main, @function
- main:
- pushl %ebp
- movl %esp, %ebp
- call test
- movl $0, %eax
- popl %ebp
- ret
- .size main, .-main
- .ident "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
- .section .note.GNU-stack,"",@progbits
從上面彙編代碼可以看出,對於沒有參數函數調用的開銷:
1. 調用函數和返回,所以需要執行一次call/ret指令對。
2. 函數內部,需要保護現場,所以需要把%ebp push到棧中,返回前,再pop出來。
3. 構造函數運行環境,將%ebp賦值爲當前的棧頂%esp。
則沒有參數函數調用開銷是5個指令。
程序2-帶參數函數調用:
- #include <stdio.h>
- void test(int a)
- {
- (a)++;
- return;
- }
- int main(int argc, char *argv[])
- {
- int a = 1;
- test(a);
- return 0;
- }
用gcc -S得到程序2的彙編代碼:
- .file "test.c"
- .text
- .globl test
- .type test, @function
- test:
- pushl %ebp
- movl %esp, %ebp
- addl $1, 8(%ebp)
- nop
- popl %ebp
- ret
- .size test, .-test
- .globl main
- .type main, @function
- main:
- pushl %ebp
- movl %esp, %ebp
- subl $20, %esp
- movl $1, -4(%ebp)
- movl -4(%ebp), %eax
- movl %eax, (%esp)
- call test
- movl $0, %eax
- leave
- ret
- .size main, .-main
- .ident "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
- .section .note.GNU-stack,"",@progbits
相比於沒有參數函數調用的開銷,帶參數函數調用多2個指令,用於傳遞參數:
movl -4(%ebp), %eax
movl %eax, (%ebp)
每個參數的傳遞時都需要2個指令。
而如果是指針參數,則函數在使用時,還得需要2個指令。
這麼看,函數調用的開銷還挺大的。
所以,當一個函數很小且調用頻繁時,應該用宏或內聯函數進行替代。
另外,雖然函數調用有開銷,但除非有特殊的必要,該用函數的地方還是應該使用函數,否則會嚴重降低代碼的可讀性和可維護性。