Swift 5.x学习笔记8-闭包补充

闭包对象的内容

之前闭包里面是为num开辟了一块堆内存,而高级语言是需要有个引用类型来引用该堆内存才能调用这块堆内存,所以

这里的sumAri无疑是个引用类型,看内存是16,指针是8个字节,所以这大约有两个指针,盲猜都可以知道是函数地址的指针,和堆地址的指针

看下汇编,callq 0x1000031c0是getSum这个函数的调用,一般函数返回的值是rax,但movq是8个字节的操作符,而这种地址存储肯定是仅挨着的,所以下面和它间隔8位的rdx就可疑了,把寄存器内存敲出来

rax是个指向sum函数的函数,从提示来看,先过掉,可以确定rax装的是能找到函数的地址的东西 ,rdx是个地址

这个地址在第16个字节-24个字节才装的5,从这个结构来看和类的结构很像,前8个字节是类型,中8个是引用计数,后8个是成员变量的值,实际上这个也是

所以这个地址就是sumAri的存储空间,存储着函数地址和变量的地址

闭包调用过程(汇编)

因为这个闭包是封存的函数地址和变量的堆对象地址,所以调用必然不是callq 0x0000124456这样一个写死的地址,写死的地址只会存在于代码段,已知确定的函数,这里的函数既不确定什么时候调用,地址也要获取,所以很快就能确定到这个函数

不确定的看下rax到底放的啥

确实是刚刚的函数地址

si跟进去

进行了rsp rbp的栈操作,我个人的理解这里的中间函数是开辟栈空间前处理一下rbp和rsp的值,还有把闭包捕获的堆空间里的变量也传给rsi,前面记录过rsi是函数传参用,看下这个r13,就知道是不是

确实这个r13的值就是之前rdx的值,也就是指向闭包捕获到的变量堆地址,再si跟进到真正的sum函数

跟进到sum函数中可以看到

1.rdi给了-0x48(%rbp)  rsi给了-0x50(%rbp),就是把寄存器的值传入了栈空间的地址,rdi就是立即数1

2.计算之前赋值给了rcx和rdx

3.把rdx再加了0x10,也就是再加了16,这是因为堆内存前面16个是存储着其它信息,从16个开始才是存储着值

4.相加之后值给了rcx

再之后rcx的值给了rax指向的内存的值,不是给寄存器(%rax)是给寄存器存储的内存赋值

读取rax寄存器,就会发现是在rdx的地址上+0x10,也就是加了16,所以这个值是实际的num1的值,这是写入了num1,然后就是返回值,返回值一般都放rax,所以从最后面往前看就好了

从函数最后看,(%rax)就是刚才存东西的地址,拿出来给了rax,然后rax给了 -0x88(%rbp)这个栈地址,然后关闭了access(底层操作,暂时不计较那么多),然后从这地址拿出来给了%rax,之后函数返回,外面就可以接受到rax了

同一个闭包,不同的对象异同

如图创建两个闭包对象,然后打印出内存地址就是rax存入的那个地址

就是红色框框的地址,rip是存储下一个指令的地址,所以是0x100002bfe + 0x9612 和0x100002c1f + 0x9601 分别是 0x10000C210和 10000C220,可以看出这两个值是挨着的

最后打印出来的值是如图的,所以可以确定,指向的函数段是相同的,指向的堆地址是不同的,所以,实际调用的时候两个闭包对象的值并不相关

闭包捕获时间点

最后结果是13,所以可知,闭包的捕获时间是返回的时候处理的,另外如果没有需要捕获的值,是不会开辟堆空间,某种意义来说,也算不上闭包了

多个捕获变量(常量)堆空间分配问题

像这样有多个值需要捕获的时候,打印地址大小,还是16,所以还是一个函数地址和堆地址的指针,函数地址没啥好说的,主要是堆地址

打上断点之后看下rdx,前面记过,这里是堆地址的指针

可以看到只有一个是值,就是c,c是十进制的12是num1,但多了个地址

继续追踪这个地址,发现存的是10

所以是一个指针留着下个变量的地址指针,这是一种树形式的数据结构,用同样的办法试了下,当再多个变量的时候这个指向的地址,会再多一个地址,这么做的目的大概是让各个变量自己管理自己的引用计数和类型,否则存的是90,谁知道存的是字符的90还是90这个数字呢

@autoclosure

自动闭包

这么传值是肯定会报错的,

但这样写就能正确运行,因为自动闭包会人为的加一个{},只要fn传的语法合法都会触发自动闭包

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值