标签:body mic 强制 参考 ima des 对象 lang const
时间 | 版本修改 |
---|---|
2020年4月12日 | 初稿 |
int main(int argc, const char * argv[]) {
void (^blk)(void) = ^{
printf("Block\n");
};
blk();
return 0;
}
//block的实现
struct __block_impl {
//由于第一个成员变量是isa指针,其实是一个OC对象。本对象中记录了block函数对应的函数指针
void *isa; //block isa指针,指向类对象(stack、malloc、global三种类型之一)
int Flags; //某些标志,暂不深入研究
int Reserved; //保留区域,以后版本升级可能会用到
void *FuncPtr; //函数指针
};
//这就是block本身对应的结构
struct __main_block_impl_0 {
//只有两个成员变量。其中impl是一个OC对象
struct __block_impl impl;
struct __main_block_desc_0* Desc; //该block的描述
//block如果捕获了一些变量,则会添加到这里
//C++中可以往struct中增加构造函数
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//静态全局函数, 函数参数就是__main_block_impl_0本身的指针。和C++和OC中调用对象成员函数类似,第一参数都是this(self)
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("Block\n");
}
//静态全局结构体
static struct __main_block_desc_0 {
size_t reserved; //保留区域,以后版本升级可能会用到
size_t Block_size; //本block大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
//由于括号嵌套较多,我这里采取特殊的换行和空格格式,旨在看清楚括号嵌套背后的实际语法。
//block表达式转换
void (*blk)(void) = (
(void (*)()) //强制转换成 void (*)(void) 类型的函数指针
& //取地址,记录该栈对象的地址
__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA) //调用struct构造函数生成该block结构体实例
);
//上述的blk的类型暂时转换成了 void (*)(void),但其实它应该是一个 struct __main_block_impl_0* 类型
//由于下列的调用中还要对其进行强制转换,所以上述转成什么类型,其实无关紧要。只要把该指针记录下来就行。
//block调用
(
(void (*)(__block_impl *)) //将函数指针强制转换成 void (*)(__block_impl *) 类型的函数指针
((__block_impl *)blk)->FuncPtr //先将 blk 强制转成 __block_impl* 类型,再取其成员变量FuncPtr。则得到一个 void * 类型的变量
)
((__block_impl *)blk) //调用参数,即将 blk 强制转成 __block_impl* 类型
;
return 0;
}
上述的源代码中我都插入了相关的详细注释,且通过换行和空格来去掉括号嵌套的影响,相信比较好理解。
这里有一个指针强转的知识点,需要科普一下。(关于main函数中blk类型的强转)
留意结构体的命名规则
标签:body mic 强制 参考 ima des 对象 lang const
原文地址:https://www.cnblogs.com/HelloGreen/p/12684721.html