本系列文章主要是对《Objective-C 高级编程》这本书做的读书笔记总结,除了这本书中的内容以外,也加上了自己对开发技术的理解和一些个人的经验分享。
Objective-C源代码 转 C++源代码的的方法
通过 clang(LLVM编译器)命令转换:
clang -rewrite-objc 源代码的文件名
先来看一个最简单的block
int main() {
void (^blk)(void) = ^{
printf("我是block\n");
};
blk();
return 0;
}
将以上源代码转换成C++源代码
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
//block结构体
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
//Block构造函数
__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;
}
};
// 将来被调用的block内部的代码:block值被转换为C的函数代码
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;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
//main 函数
int main() {
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
return 0;
}
看下面的代码
^ {
printf("我是block\n");
};
可以看到,变换后的源代码中也含有相同的表达式
static void __main_block_func_0(struct __main_block_impl_0 * __cself) {
printf("我是block\n");
}
通过block使用的匿名函数实际上被作为简单的C语言函数来处理。根据block语法所属的函数名(此处为main)和该block语法在该函数出现的顺序值(此处为0)来给函数命名 __main_block_func_0
该函数的参数 __cself 相当于C++实例方法中指向实例自身的变量this,或是Object-C实例方法中指向对象自身的变量self,即参数 __cself 为指向block值的变量。
这里的 __main_block_func_0 函数并没有使用到 __cself。使用 __cself 的例子将在后面介绍,我们先来看看该参数的声明,参数 __cself 是 __main_block_func_0 结构体的指针。
struct __main_block_impl_0 * __cself
该结构体的声明如下:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0 * Desc;
}
第一个成员变量是 impl,我们先来看一下 __block_impl 结构体的声明。
struct __block_impl {
void *isa;
int Flags; // 标志
int Reserved;
void *FuncPtr;
}
接下来我们看一下第二个成员变量 Desc指针
struct __main_block_desc_0 {
unsigned long reserved; // 版本升级所需的区域
unsigned long Block_size; // block的大小
}
那么,我们再来看一下初始化这些结构体的 _main_block_impl_0 结构体的构造函数
__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;
}
NSConcreteStackBlock用于初始化 __block_impl结构体 的isa成员,后面将会讲解。我们先来看一下该构造函数的调用。
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
因为转换较多,所以看起来比较不清楚,我们来去掉转换的部分,再看一下
struct __main_block_impl_0 temp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
struct __main_block_impl_0 *blk = &temp;
这样就容易理解了。该源代码将 __main_block_impl_0结构体 类型的自动变量,赋值给 __main_block_impl_0结构体指针类型的变量blk
下面就来看看 __main_block_impl_0结构体实例构造参数。
__main_block_impl_0 (__main_block_func_0, &__main_block_desc_0_DATA);
第一个参数是由block语法转换为C语言函数指针。第二个参数是作为静态全局变量初始化的 __main_block_desc_0 结构体的实例指针。
以下为 __main_block_desc_0 结构体实例的初始化部分代码,可以看到源代码使用 __main_block_impl_0 结构体的实例大小,进行初始化。
static struct __main_block_desc_0 __main_block_desc_0_DATA = {
0,
sizeof(struct __main_block_impl_0)
};
下面看看栈上的 __main_block_impl_0结构体 实例是如何根本这些参数进行初始化的。
struct __main_block_impl_0 {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
struct __main_block_desc_0* Desc;
};
该结构体根据构造函数会像下面这样进行初始化
isa = &_NSConcreteStackBlock;
Flags = 0;
Reserved = 0;
FuncPtr = __main_block_func_0;
Desc = &__main_block_desc_0_DATA;
将 __main_block_func_0 函数指针赋给成员变量 FuncPtr
blk();
转换后的源代码如下
((void (*)(struct __block_impl *))((struct __block_impl *)blk)->FuncPtr)((struct __block_impl *)blk);
去掉转换部分:
(*blk -> impl.FuncPtr)(blk);
这就是简单地使用函数指针调用函数。