block 解析 - 局部變數

來源:互聯網
上載者:User

標籤:des   style   blog   color   使用   os   檔案   io   

局部變數block內使用局部變數,一般都是截獲變數(唯讀),截獲離block初始化最近的一次的值。引用官方文檔:
  1. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope. 
 我們做一個測試,瞭解一下原理代碼如下:
void main1(){    char *_para1="a";    printf("init _para1:%s,%p,%p\n",_para1,_para1,&_para1);    void(^testBlock)(void)=^{        printf("exute _para1:%s,%p,%p\n",_para1,_para1,&_para1);    };    _para1="b";    printf("before _para1:%s,%p,%p\n",_para1,_para1,&_para1);    testBlock();    printf("after _para1:%s,%p,%p\n",_para1,_para1,&_para1);}

 輸出一下結果:

init _para1:a,0x97f70,0x27d70988before _para1:b,0x97fa5,0x27d70988exute _para1:a,0x97f70,0x165839e4after _para1:b,0x97fa5,0x27d70988
 我們可以藉助  clang -rewrite-objc 轉換.c檔案得到.cpp檔案,也可以轉換.m也可以得到cpp檔案(可能會有些報錯)以下是部分轉換後的代碼//這裡就是block對象的結構
//imp:函數指標對象,FuncPtr指向具體block實現的函數
//_person2:截獲的變數
//isa、flags、funcptr、desc後面會說道。
struct __block_impl {  void *isa;  int Flags;  int Reserved;  void *FuncPtr;};
struct __main1_block_impl_0 {  struct __block_impl impl;  struct __main1_block_desc_0* Desc;  char *_para1;  __main1_block_impl_0(void *fp, struct __main1_block_desc_0 *desc, char *__para1, int flags=0) : _para1(__para1) {    impl.isa = &_NSConcreteStackBlock;    impl.Flags = flags;    impl.FuncPtr = fp;    Desc = desc;  }};
//block實現的函數
static void __main1_block_func_0(struct __main1_block_impl_0 *__cself) {  char *_para1 = __cself->_para1; // bound by copy        printf("exute _para1:%s,%p,%p\n",_para1,_para1,&_para1);    }
//block對象的描述資訊(大小等等)
static struct __main1_block_desc_0 {  size_t reserved;  size_t Block_size;} __main1_block_desc_0_DATA = { 0, sizeof(struct __main1_block_impl_0)};
//這是objc測試函數test
void main1(){    char *_para1="a";    printf("init _para1:%s,%p,%p\n",_para1,_para1,&_para1);    void(*testBlock)(void)=(void (*)())&__main1_block_impl_0((void *)__main1_block_func_0, &__main1_block_desc_0_DATA, _para1);    _para1="b";    printf("before _para1:%s,%p,%p\n",_para1,_para1,&_para1);    ((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);    printf("after _para1:%s,%p,%p\n",_para1,_para1,&_para1);}

簡單分析block截獲變數:

 1).block初始化
void(*testBlock)(void)=(void (*)())&__main1_block_impl_0((void *)__main1_block_func_0, &__main1_block_desc_0_DATA, _para1);
傳入了參數:函數指標、block描述、外部變數_para1,這時候在block內部對_para1進行了引用,即block的結構體成員_para1引用了的是 這個地址 0x97f70
 : _para1(__para1) 

 之後又對_para1做了修改,重新指向了 0x97fa5這塊記憶體,但是不會影響block結構體成員_para1,因為成員_para1指向的是0x97f70。

2).執行block
((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);

其實還是調用了block對象裡的函數對象(_block_imp1)的函數指標(FuncPtr) 所指向的函數__main1_block_func_0,並把block自己作為參數傳遞進去。

static void __main1_block_func_0(struct __main1_block_impl_0 *__cself) {  char *_para1 = __cself->_para1; // bound by copy        printf("exute _para1:%s,%p,%p\n",_para1,_para1,&_para1);    }

值得注意的的是,我們在執行之前對_para1修改,但是並沒有對block內部產生影響(只是把局部變數_para1重新指向另一塊記憶體(0x97fa5)),而在構造block的時候,block對象內部對截獲的變數做了引用(引用的是0x97f70),放在(char *_para1)裡,執行block的時候,直接調用函數__main1_block_func_0,函數內部,是引用了block結構體的成員_para1,所以會有這樣的結果。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.