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修飾符,只是為了表明該函數只在該文件中可見!也就是說,在同一個工程中,就算在其他文件中也出現同名、同參數的函數也不會引起函數重復定義的錯誤!**
實踐到這里,對于內聯函數終的理解,終于加深理解和記憶了!!
總結
以上是生活随笔為你收集整理的ios内联函数 inline的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx 503错误总结
- 下一篇: 怎么创建具有真实纹理的CG场景岩石?