内联函数 inline

 

  • 引入内联函数是为了解决函数调用效率的问题

  • 由于函数之间的调用,会从一个内存地址调到另外一个内存地址,当函数调用完毕之后还会返回原来函数执行的地址。函数调用会有一定的时间开销,引入内联函数就是为了解决这一问题。

  • 那么引用内联函数到底有什么区别呢?万一面试问到了,那只能回答”为了解决函数调用效率的问题”?

  • 代码一

    说明:定义一个add(int,int)函数并声明为static inline,并调用。

    头文件:inline.h

//  inline.h
//  inline
//  Created by fenglh on 15/8/24.
//  Copyright (c) 2015年 fenglh. All rights reserved.

#ifndef inline_inline_h
#define inline_inline_h

static inline int add(int a, int b){
    return a+b;
}
#endif

 

//  main.m
//  inline
//  Created by fenglj on 15/8/24.
//  Copyright (c) 2015年 fenglh. All rights reserved.

#import <Foundation/Foundation.h>
#import "inline.h"

int main(int argc, const char * argv[]) {
    int c = add(1, 2);
    return 0;
}

查看main.m的汇编文件,如下:

.section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
Lfunc_begin0:
    .loc    2 14 0                  ## /Users/fenglihai/Desktop/inline/inline/main.m:14:0
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    ##DEBUG_VALUE: main:argc <- EDI
    ##DEBUG_VALUE: main:argv <- RSI
Ltmp3:
    ##DEBUG_VALUE: main:c <- 3
    xorl    %eax, %eax
    .loc    2 17 5 prologue_end     ## /Users/fenglihai/Desktop/inline/inline/main.m:17:5
Ltmp4:
    popq    %rbp
    retq

代码二

说明:定义一个add(int,int)函数并调用。

头文件:Header.h

//  Header.h
//  notInline
//  Created by fenglh on 15/8/25.
//  Copyright (c) 2015年 fenglh. All rights reserved.

#ifndef notInline_Header_h
#define notInline_Header_h

 int add(int a, int b){
    return a+b;
}

#endif

.m文件:main.m

//  main.m
//  notInline
//  Created by fenglh on 15/8/25.
//  Copyright (c) 2015年 fenglh. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Header.h"

int main(int argc, const char * argv[]) {
    int c = add(1,2);
    return 0;
}

查看main.m的汇编文件,如下:

    .section    __TEXT,__text,regular,pure_instructions
    .globl  _add
    .align  4, 0x90
_add:                                   ## @add
Lfunc_begin0:
    .file   3 "/Users/fenglihai/Desktop/notInline/notInline" "Header.h"
    .loc    3 12 0                  ## /Users/fenglihai/Desktop/notInline/notInline/Header.h:12:0
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    .loc    3 13 5 prologue_end     ## /Users/fenglihai/Desktop/notInline/notInline/Header.h:13:5
Ltmp3:
    movl    -4(%rbp), %esi
    addl    -8(%rbp), %esi
    movl    %esi, %eax
    popq    %rbp
    retq
Ltmp4:
Lfunc_end0:
    .cfi_endproc

    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
Lfunc_begin1:
    .loc    2 12 0                  ## /Users/fenglihai/Desktop/notInline/notInline/main.m:12:0
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp5:
    .cfi_def_cfa_offset 16
Ltmp6:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp7:
    .cfi_def_cfa_register %rbp
    subq    $32, %rsp
    movl    $1, %eax
    movl    $2, %ecx
    movl    $0, -4(%rbp)
    movl    %edi, -8(%rbp)
    movq    %rsi, -16(%rbp)
    .loc    2 13 13 prologue_end    ## /Users/fenglihai/Desktop/notInline/notInline/main.m:13:13
Ltmp8:
    movl    %eax, %edi
    movl    %ecx, %esi
    callq   _add
    xorl    %ecx, %ecx
    movl    %eax, -20(%rbp)
    .loc    2 14 5                  ## /Users/fenglihai/Desktop/notInline/notInline/main.m:14:5
    movl    %ecx, %eax
    addq    $32, %rsp
    popq    %rbp
    retq

上面2段代码可以看出,只有add函数的定义不一样,一个是加了static inline修饰,而另外一个没有。再对比一下汇编代码,发现的确有很大的不一样呀!!!给人第一感觉,有用static inline修饰的汇编之后的代码比没有static inline修饰的的汇编之后的代码简洁的多了!!

其次,在没有调用static inline修饰add函数的main.m汇编代码中,add函数是有单独的汇编代码的! ä½¿ç¨åèå½æ°çæ±ç¼ä»£ç 

而没有使用内联函数的main.m汇编代码中,仅仅只有main函数的汇编代码! æ²¡æ使ç¨åèå½æ°çæ±ç¼ä»£ç  

 再看看使用了内联函数的main.m汇编代码: è¿éåå¾çæè¿°

 

对比两者的mian.m的汇编代码,可以发现,没有使用`static inline修饰的内联函数的mian函数汇编代码中,会出现 call 指令!这就是区别!调用call指令就是就需要: 
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈 
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。

结论

1.使用inline修饰的函数,在编译的时候,会把代码直接嵌入调用代码中。就相当于用#define 宏定义来定义一个add 函数那样!与#define的区别是: 
1)#define定义的格式要有要求,而使用inline则就行平常写函数那样,只要加上`inline即可! 
2)使用#define宏定义的代码,编译器不会对其进行参数有效性检查,仅仅只是对符号表进行替换。 
3)#define宏定义的代码,其返回值不能被强制转换成可转换的适合的转换类型。可参考百度文科 关于inline

2.在inline加上`static修饰符,只是为了表明该函数只在该文件中可见!也就是说,在同一个工程中,就算在其他文件中也出现同名、同参数的函数也不会引起函数重复定义的错误!**

实践到这里,对于内联函数终的理解,终于加深理解和记忆了!!

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值