因爲在學習使用UIScrollVew開發的過程當中,碰到下面這個屬性(設置內邊距):ios
@property(nonatomic) UIEdgeInsets scrollIndicatorInsets; // default is UIEdgeInsetsZero. adjust indicators inside
光看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;
原來是這樣一個結構體!~ 隨之,看到和UIEdgeInsets
相關的使用方法,列舉部分:xcode
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; } ...
看着上面的代碼,又出現了一個我不認識的東西UIKIT_STATIC_INLINE
,繼續點進去查看發現這是這麼一個宏:ide
#define UIKIT_STATIC_INLINE static inline
哦,原來它的意思是告訴編譯器這個函數是一個靜態的內聯函數!內聯函數?好耳熟啊,可是想不起來具體有什麼做用了,因而百度百度!!得出的能令我印象深入的結論是:函數
引入內聯函數是爲了解決函數調用效率的問題學習
因爲函數之間的調用,會從一個內存地址調到另一個內存地址,當函數調用完畢以後還會返回原來函數執行的地址。函數調用會有必定的時間開銷,引入內聯函數就是爲了解決這一問題。測試
那麼引用內聯函數到底有什麼區別呢?萬一面試問到了,那隻能回答」爲了解決函數調用效率的問題」?若是面試官再問「如何解決呢?」,那豈不是歇菜了!!不如本身寫代碼測試看看?!!打開xcode..ui
說明:定義一個add(int,int)函數並聲明爲static inline
,並調用。atom
頭文件:inline.hurl
// 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
.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; }
查看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的下一條指令就會轉去執行子程序)。
恩恩,對於彙編就不扯淡了,憑藉着上學時候學過點彙編只能深刻到這裏了!唉!那麼得知,影響效率的緣由就是在解決在call調用這裏了!!
1.使用inline
修飾的函數,在編譯的時候,會把代碼直接嵌入調用代碼中。就至關於用#define 宏定義來定義一個add 函數那樣!與#define的區別是:
1)#define定義的格式要有要求,而使用inline
則就行日常寫函數那樣,只要加上`inline
便可!
2)使用#define宏定義的代碼,編譯器不會對其進行參數有效性檢查,僅僅只是對符號表進行替換。
3)#define宏定義的代碼,其返回值不能被強制轉換成可轉換的適合的轉換類型。可參考百度文科 關於inline
2.在inline
加上`static
修飾符,只是爲了代表該函數只在該文件中可見!也就是說,在同一個工程中,就算在其餘文件中也出現同名、同參數的函數也不會引發函數重複定義的錯誤!**
實踐到這裏,對於內聯函數終的理解,終於加深理解和記憶了!!