zoukankan      html  css  js  c++  java
  • 函数调用开销

    做了几个实验,简单学习了解一下函数调用的开销。
    程序1—没有参数的函数调用:
    [cpp] view plaincopyprint?
    #include <stdio.h>  
    void test() 

     return; 

    int main(int argc, char *argv[]) 

     test(); 
     return 0; 

     

    用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个指令。
    这么看,函数调用的开销还挺大的。
    所以,当一个函数很小且调用频繁时,应该用宏或内联函数进行替代。
    另外,虽然函数调用有开销,但除非有特殊的必要,该用函数的地方还是应该使用函数,否则会严重降低代码的可读性和可维护性。

  • 相关阅读:
    Mac php使用gd库出错 Call to undefined function imagettftext()
    centos 使用 locate
    Mac HomeBrew 安装 mysql
    zsh 命令提示符 PROMPT
    新的开始
    Java 面试题分析
    Java NIO Show All Files
    正确使用 Volatile 变量
    面试题整理 2017
    有10阶梯, 每次走1,2 or 3 阶,有多少种方式???
  • 原文地址:https://www.cnblogs.com/byfei/p/14104513.html
Copyright © 2011-2022 走看看