block 的内存结构衍生出来的面试题
Posted boch2436
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了block 的内存结构衍生出来的面试题相关的知识,希望对你有一定的参考价值。
今天在群里看到大佬们在讨论一个面试题,问如下代码在 32bit 和 64bit 系统上分别报什么错误:
#import <Foundation/Foundation.h>
int main()
{
void (^block)(void) = nil;
block();
return 0;
}
虽然有大佬一下子说出了答案,但我仍然一脸懵逼,后来经人提醒,这个考察 block 在内存中的结构,于是赶紧做了如下实验终于弄懂了为什么。
- 实验
将以上代码保存为block_test.m
,在命令行编译成 C++:clang -rewrite-objc -fobjc-arc block_test.m
,打开同一目录下生成的block_test.cpp
文件,截取如下关键代码:
// 注释①
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
int main()
{
void (*block)(void) = __null;
// 注释 ②
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
return 0;
}
-
解释:
- 注释①所在的结构体是 block 在内存中的数据结构。
- 注释②是一个函数调用语句,可以简化成:
((__block_impl *)block)->FuncPtr(block)
,即调用__block_impl
类型指针指向的结构体中FuncPtr
指向的函数,由于该结构体指针指向的内容为 null,因此FuncPtr
指向的位置显然不是一个函数,所以该指针指向的位置会发生一个EXC_BAD_ACCESS
错误。 FuncPtr
指向的位置是多少呢?根据上述__block_impl
中各成员变量的排列可知FuncPtr
的偏移是sizeof(void *) + sizeof(int) + sizeof(int)
,另外还需要考虑结构体内存对齐,参考这个链接,所以在 32bit 系统中,偏移:4 + 4 + 4 = 0x0C
;64bit 系统中,偏移:8 + 8 = 0x10
-
结论:
- 答案:在 32bit 系统中报错:
EXC_BAD_ACCESS(address = 0x0C)
,在 64bit 系统中报错EXC_BAD_ACCESS(address = 0x10)
- block 本质是一个结构体,在探究 block 相关的问题时,转换成
C++
代码后往往就可以一目了然,比如weakSelf 为什么可以解决循环引用
- 答案:在 32bit 系统中报错:
以上是关于block 的内存结构衍生出来的面试题的主要内容,如果未能解决你的问题,请参考以下文章