【转】ios内联函数 inline

ios内联函数 inline

缘由

由于在学习使用UIScrollVew开发的过程中,碰到下面这个属性(设置内边距):

@property(nonatomic)         UIEdgeInsets                 scrollIndicatorInsets;          // default is UIEdgeInsetsZero. adjust indicators inside 
  • 1

光看UIEdgeInsets这个类型,一时还不知道它的具体内部结构是怎么样的,于是继续点进去发现它的定义如下:

typedef struct UIEdgeInsets {
    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to ‘outset‘
} UIEdgeInsets;
  • 1
  • 2
  • 3

原来是这样一个结构体!~ 随之,看到和UIEdgeInsets相关的使用方法,列举部分:

UIKIT_STATIC_INLINE UIEdgeInsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right) {
    UIEdgeInsets insets = {top, left, bottom, right};
    return insets;
}

UIKIT_STATIC_INLINE UIOffset UIOffsetMake(CGFloat horizontal, CGFloat vertical) {
    UIOffset offset = {horizontal, vertical};
    return offset;
}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

看着上面的代码,又出现了一个我不认识的东西UIKIT_STATIC_INLINE,继续点进去查看发现这是这么一个宏:

#define UIKIT_STATIC_INLINE static inline
  • 1

哦,原来它的意思是告诉编译器这个函数是一个静态的内联函数!内联函数?好耳熟啊,但是想不起来具体有什么作用了,于是百度百度!!得出的能令我印象深刻的结论是:

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

实践

那么引用内联函数到底有什么区别呢?万一面试问到了,那只能回答”为了解决函数调用效率的问题”?如果面试官再问“如何解决呢?”,那岂不是歇菜了!!不如自己写代码测试看看?!!打开xcode..

代码一

说明:定义一个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

.m文件:main.m

//  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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

查看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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

代码二

说明:定义一个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

.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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

查看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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63


上面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的下一条指令就会转去执行子程序)。

恩恩,对于汇编就不扯淡了,凭借着上学时候学过点汇编只能深入到这里了!唉!那么得知,影响效率的原因就是在解决在call调用这里了!!

结论

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

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

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

时间: 2024-08-24 15:50:39

【转】ios内联函数 inline的相关文章

iOS OC内联函数 inline的详解

inline 在iOS中的一些框架中,static inline是经常出现的关键字组合. static自不用多说,表示在当前文件中应用,如 static A, 在其它文件中也可以出现static A.不会导致重名的错误. inline.内联函数. 作用:替代宏. (如果你在看框架时,看到inline不解,搜索到这篇文章,看到这里可以不用看下面的详述了) 在框架中出现inline时,如YYKit框架.我们稍加观察就会发现它出现在.h文件中. such as: static inline CGFlo

内联函数inline

1:使用inline函数的时候,必须使函数体和inline说明结合一起,否则编译器将视他为普通函数处理: false: inline void Coord::setcoord(int a,int b); true: inline void Coord::setcoord(int a ,int b) { x = a; y =b; } 2:通常只有较短的成员函数才会定义为内联函数. 3:内联函数是编译时展开到调用处.

内联函数 inline 漫谈

内联函数存在的结论是: 引入内联函数是为了解决函数调用效率的问题 由于函数之间的调用,会从一个内存地址调到另外一个内存地址,当函数调用完毕之后还会返回原来函数执行的地址.函数调用会有一定的时间开销,引入内联函数就是为了解决这一问题. 不用inline修饰的函数, 汇编时会出现 call 指令.调用call指令就是就需要: (1)将下一条指令的所在地址入栈 (2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序). 原因 因为调用函数实际上将程序执行顺序转移到函数所存放在内存

C++ 内联函数inline

http://blog.csdn.net/u011327981/article/details/50601800 1.  内联函数 在C++中我们通常定义以下函数来求两个整数的最大值: 复制代码 代码如下: int max(int a, int b){ return a > b ? a : b;} 为这么一个小的操作定义一个函数的好处有: ① 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多 ② 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多

内联函数 inline

(一)inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline int min(int first, int secend) {/****/}; inline 函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数.与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义.当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同.对于由两个文件comput

【转】新手入门:关于C++中的内联函数(inline)

原文地址:http://www.pconline.com.cn/pcedu/empolder/gj/c/0503/563879.html 在c++中,为了解决一些频繁调用的小函数大量消耗栈空间或者是叫栈内存的问题,特别的引入了inline修饰符,表示为内联函数. 可能说到这里,很多人还不明白什么是栈空间,其实栈空间就是指放置程序的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,如果频繁大量的使用就会造成因栈空间不足所造成的程序出错的问题,函数的死循环递归调用的最终结果就是导致栈内存

c++中的内联函数inline

文章链接: 问题描述:类中成员函数缺省默认是内联的,如果在类定义时就在类内给出函数定义,那当然最好.如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的.内联函数的inline要加在函数前面,不可以加在声明前面. 1 class A 2 { 3 public:void Foo(int x, int y) { } // 自动地成为内联函数 4 } 5 //正确写法: 6 // 头文件 7 class A 8 { 9 public: 10 void

(转)内联(inline)函数与虚函数(virtual)的讨论

本文转自: http://topic.csdn.net/t/20051220/09/4469273.html 函数的inline属性是在编译时确定的, 然而,virtual的性质是在运行时确定的,这两个不能同时存在,只能有一个选择,文件中的inline关键字只是对编译器的建议,编译器是否采纳是编译器的事情. 1.内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的. 2.我们之所以能看到一些象内联函数的虚函数,是因为某个函数是否是内联函数不是由我们说的算,而是由编译器决定的.我们只能向

内联函数详解

什么是内联性和外联函数 类的成员函数可以分为内联函数和外联函数.内联函数是指那些定义在类体内的成员函数,即该函数的函数体放在类体内.而说明在类体内,定义在类体外的成员函数叫外联函数.外联函数的函数体在类的实现部分. 内联函数在调用时不是像一般的函数那样要转去执行被调用函数的函数体,执行完成后再转回调用函数中,执行其后语句,而是在调用函数处用内联函数体的代码来替换,这样将会节省调用开销,提高运行速度. 内联函数与前面讲过的带参数的宏定义进行一下比较,它们的代码效率是一样的,但是内联函数要优于宏定义