網站首頁 編程語言 正文
指針與指針變量
通俗的理解:
指針:內存地址
指針變量:存放內存地址的變量
指針變量的指針:指針變量自身的內存地址
Person *p = [Person new]
右邊isa為:對象的內存地址 - 指針
p為:指針變量
左邊isa為:指針變量的內存地址 - 指針變量的指針
block捕獲變量方式
對局部變量捕獲有兩種形式:1、值捕獲(局部自動變量) 2、指針捕獲(局部靜態(tài)變量);全局變量無需捕獲,可直接進行訪問。
clang -rewrite-objc **.m -o **.cpp
不同場景下轉換成C++代碼結果如下(嫌代碼長不想看的直接看代碼下面的結論)
值捕獲
指針變量的捕獲
block內部用一個新的指針變量來接收原指針變量。接收后,兩個指針變量里面存儲的值都是對象的內存地址,所以也可以說是值的捕獲。
局部自動變量:
int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [Person new]; void (^block)(void) = ^{ NSLog(@"%@",p); }; block(); } return 0; }
struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; Person *p; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_p, int flags=0) : p(_p) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { Person *p = __cself->p; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_7w_wgxxl_655s9g6tms_7z44s6w0000gn_T_main_f76e59_mi_0,p); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new")); void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, p, 570425344)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
代碼分析,生成的__main_block_impl_0結構體里面創(chuàng)建了一個指針變量p,main函數里面的__main_block_impl_0初始化時,傳入的也是指針變量p。所以block對局部自動變量采用的捕獲方式是指針變量的捕獲,也就是值捕獲。
指針捕獲
對指針變量自身指針的捕獲
block內部用一個新的指針來接收(指向)原指針變量自身的地址。
局部靜態(tài)變量:
int main(int argc, const char * argv[]) { @autoreleasepool { static Person *p = nil; p = [Person new]; void (^block)(void) = ^{ NSLog(@"%@",p); }; block(); } return 0; }
struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; Person **p; __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person **_p, int flags=0) : p(_p) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { Person **p = __cself->p; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_7w_wgxxl_655s9g6tms_7z44s6w0000gn_T_main_bd39c2_mi_0,(*p)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; static Person *p = __null; p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new")); void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &p, 570425344)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
代碼分析,生成的__main_block_impl_0結構體里面創(chuàng)建了一個指針*p,main函數里面的__main_block_impl_0初始化時,傳入的是指針變量p的地址&p。所以block對局部靜態(tài)變量采用的捕獲方式是指針變量自身地址的捕獲,也就是指針捕獲。
__block修飾的變量
int main(int argc, const char * argv[]) { @autoreleasepool { __block Person *p = [Person new]; void (^block)(void) = ^{ NSLog(@"%@",p); }; block(); } return 0; }
struct Person_IMPL { struct NSObject_IMPL NSObject_IVARS; }; struct __Block_byref_p_0 { void *__isa; __Block_byref_p_0 *__forwarding; int __flags; int __size; void (*__Block_byref_id_object_copy)(void*, void*); void (*__Block_byref_id_object_dispose)(void*); Person *p; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_p_0 *p; // by ref __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_p_0 *_p, int flags=0) : p(_p->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } }; static void __main_block_func_0(struct __main_block_impl_0 *__cself) { __Block_byref_p_0 *p = __cself->p; // bound by ref NSLog((NSString *)&__NSConstantStringImpl__var_folders_7w_wgxxl_655s9g6tms_7z44s6w0000gn_T_main_6c171f_mi_0,(p->__forwarding->p)); } static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->p, (void*)src->p, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->p, 8/*BLOCK_FIELD_IS_BYREF*/);} static struct __main_block_desc_0 { size_t reserved; size_t Block_size; void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); void (*dispose)(struct __main_block_impl_0*); } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_p_0 p = {(void*)0,(__Block_byref_p_0 *)&p, 33554432, sizeof(__Block_byref_p_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"))}; void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_p_0 *)&p, 570425344)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
代碼分析,使用__block修飾的指針變量p,會被轉換為__Block_byref_p_0的結構體,結構體內持有p。main函數里面初始化__main_block_impl_0時傳入的是__Block_byref_p_0的地址,訪問p時,通過__Block_byref_p_0的__forwarding指針進行訪問。其實就相當于block內部捕獲了__Block_byref_p_0的指針,通過指針去訪問__Block_byref_p_0持有的p。所以__block修飾的變量本質上也相當于是一種指針捕獲,只不過不是直接捕獲指針變量p的自身地址。
值捕獲能否重新賦值? 進行值拷貝時,block內部同名指針變量如果執(zhí)行重新賦值操作,相當于使內部的指針變量指向了一個新的對象,再對此對象進行任何操作都與原指針變量指向的原對象無關,所以不能進行重新賦值。
指針捕獲能否重新賦值? block內部將block外部的指針變量的指針賦值給一個新的指針,block內部、外部的指針都指向的是同一個指針變量。如果進行賦值操作,操作的是同一個指針變量,所以可以進行重新賦值。
關于block延伸的知識點
如果文章看到了這里,相信對值捕獲和指針捕獲已經有了一個清晰的認識,那么可以自行思考以下幾個問題,看是否真的理解了block,文章沒有的答案放在評論區(qū)
- 值捕獲能否在block內被重新賦值?如果是靜態(tài)變量呢?(文中已有)
- 經__block修飾變量生成的持有變量的結構體里面__forwarding的意義在于什么?
- 使用block有什么需要注意的點,如何去解決?
總結
原文鏈接:https://juejin.cn/post/7060899012806705188
相關推薦
- 2022-06-08 淺談C#多線程下的調優(yōu)_C#教程
- 2022-05-11 使用git命令上傳代碼_其它綜合
- 2022-04-01 使用lsof命令恢復已刪除文件(正在使用的文件)
- 2023-04-07 Python實現(xiàn)SVM支持向量機的示例代碼_python
- 2022-03-27 C++中兩種字符串定義方式和區(qū)別介紹_C 語言
- 2022-09-24 python實現(xiàn)梯度下降求解邏輯回歸_python
- 2024-03-22 【IDEA】maven項目刷新依賴的兩種方式
- 2024-01-07 使用 SpringSecurity 發(fā)送POST請求出現(xiàn) 403
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支