Block对象变量捕获(三)

Block对象变量捕获(三),第1张

前面已经说过Block对基本类型变量的捕获,现在来看看Block对对象变量的捕获。先看看下面几个问题

1、对象的局部变量捕获和基本数据类型有点区别,对象的局部auto变量捕获是指针捕获不是值捕获,所以捕获的内容会受外部变量的影响

2、因为block捕获了auto变量所以block是NSStackBlock,在ARC下将block赋值给__strong指针时会自动将栈上的block复制到堆上,block由NSStackBlock变为NSMallocBlock

1、这里Person虽然是局部变量,但是不是在离开作用域时(离开大括号)被释放,因为Person在被block捕获时被block强引用了,引用计数加了1,只有当引用计数为0时才会被释放。当block调用完从堆上移除时,会调用block内部的dispose函数,dispose函数内部会调用_Block_object_dispose函数,_Block_object_dispose函数会自动释放引用的auto变量(release),person的引用计数减1,此时person的引用计数为0被释放

2、block为NSMallocBlock的原因与问题一一样,这里需要说的是,只有在NSMallocBlock下才会对auto变量产生强引用,如果block是在栈上,将不会对auto变量产生强引用。

如果block被拷贝到堆上,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的 *** 作,形成强引用(retain)或者弱引用

在问题二中有说到,堆上的Block会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的 *** 作,形成强引用(retain)或者弱引用。这里的person的修饰符为weak,所以block会对其产生弱引用,引用计数不会加1,当出作用域时person会被释放

1、self为对象局部auto变量,所以是指针捕获,内部的值会受外部的影响

2、block对self产生了一个强引用

Block变量捕获详解(一)

Block的三种类型(二)

__block修饰符(四)

Block循环引用(五)

以在linux下为例,适用gcc编译一个名为testc的文件,文件里面有个函数定义void test(void);

#include "stdioh"

void test(void)

{

printf("test!!!\n");

}

int main(int arg, void args[])

{

test();

return 0;

}

编译命令gcc -o test testc 生成test可执行文件。

用readelf -s test命令可以读出test文件里面的各个段的大小。

Symbol table 'dynsym' contains 6 entries:

Num: Value Size Type Bind Vis Ndx Name

0: 00000000 0 NOTYPE LOCAL DEFAULT UND

1: 00000000 401 FUNC GLOBAL DEFAULT UND puts@GLIBC_20 (2)

2: 00000000 391 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_20 (2)

3: 0804845c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used

4: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses

5: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

Symbol table 'symtab' contains 71 entries:

Num: Value Size Type Bind Vis Ndx Name

0: 00000000 0 NOTYPE LOCAL DEFAULT UND

1: 08048114 0 SECTION LOCAL DEFAULT 1

2: 08048128 0 SECTION LOCAL DEFAULT 2

3: 08048148 0 SECTION LOCAL DEFAULT 3

4: 08048174 0 SECTION LOCAL DEFAULT 4

5: 080481d4 0 SECTION LOCAL DEFAULT 5

6: 08048232 0 SECTION LOCAL DEFAULT 6

7: 08048240 0 SECTION LOCAL DEFAULT 7

8: 08048260 0 SECTION LOCAL DEFAULT 8

9: 08048268 0 SECTION LOCAL DEFAULT 9

10: 08048280 0 SECTION LOCAL DEFAULT 10

11: 08048298 0 SECTION LOCAL DEFAULT 11

12: 080482d8 0 SECTION LOCAL DEFAULT 12

13: 0804843c 0 SECTION LOCAL DEFAULT 13

14: 08048458 0 SECTION LOCAL DEFAULT 14

15: 08048468 0 SECTION LOCAL DEFAULT 15

16: 0804946c 0 SECTION LOCAL DEFAULT 16

17: 08049474 0 SECTION LOCAL DEFAULT 17

18: 0804947c 0 SECTION LOCAL DEFAULT 18

19: 08049480 0 SECTION LOCAL DEFAULT 19

20: 08049548 0 SECTION LOCAL DEFAULT 20

21: 0804954c 0 SECTION LOCAL DEFAULT 21

22: 08049564 0 SECTION LOCAL DEFAULT 22

23: 08049570 0 SECTION LOCAL DEFAULT 23

24: 00000000 0 SECTION LOCAL DEFAULT 24

25: 00000000 0 SECTION LOCAL DEFAULT 25

26: 00000000 0 SECTION LOCAL DEFAULT 26

27: 00000000 0 SECTION LOCAL DEFAULT 27

28: 080482fc 0 FUNC LOCAL DEFAULT 12 call_gmon_start

29: 00000000 0 FILE LOCAL DEFAULT ABS crtstuffc

30: 0804946c 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__

31: 08049474 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__

32: 0804947c 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__

33: 08049570 1 OBJECT LOCAL DEFAULT 23 completed4583

34: 0804956c 0 OBJECT LOCAL DEFAULT 22 p4582

35: 08048320 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux

36: 08048354 0 FUNC LOCAL DEFAULT 12 frame_dummy

37: 00000000 0 FILE LOCAL DEFAULT ABS crtstuffc

38: 08049470 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__

39: 08049478 0 OBJECT LOCAL DEFAULT 17 __DTOR_END__

40: 08048468 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__

41: 0804947c 0 OBJECT LOCAL DEFAULT 18 __JCR_END__

42: 08048414 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux

43: 00000000 0 FILE LOCAL DEFAULT ABS testc

44: 08049480 0 OBJECT GLOBAL DEFAULT 19 _DYNAMIC

45: 08048458 4 OBJECT GLOBAL DEFAULT 14 _fp_hw

46: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_end

47: 08049568 0 OBJECT GLOBAL HIDDEN 22 __dso_handle

48: 0804840c 5 FUNC GLOBAL DEFAULT 12 __libc_csu_fini

49: 00000000 401 FUNC GLOBAL DEFAULT UND puts@@GLIBC_20

50: 08048280 0 FUNC GLOBAL DEFAULT 10 _init

51: 0804837c 24 FUNC GLOBAL DEFAULT 12 test

52: 080482d8 0 FUNC GLOBAL DEFAULT 12 _start

53: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_start

54: 080483bc 79 FUNC GLOBAL DEFAULT 12 __libc_csu_init

55: 08049570 0 NOTYPE GLOBAL DEFAULT ABS __bss_start

56: 08048394 40 FUNC GLOBAL DEFAULT 12 main

57: 00000000 391 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_

58: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __init_array_end

59: 08049564 0 NOTYPE WEAK DEFAULT 22 data_start

60: 0804843c 0 FUNC GLOBAL DEFAULT 13 _fini

61: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_end

62: 08049570 0 NOTYPE GLOBAL DEFAULT ABS _edata

63: 0804954c 0 OBJECT GLOBAL HIDDEN 21 _GLOBAL_OFFSET_TABLE_

64: 08049574 0 NOTYPE GLOBAL DEFAULT ABS _end

65: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __init_array_start

66: 0804845c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used

67: 08049564 0 NOTYPE GLOBAL DEFAULT 22 __data_start

68: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses

69: 0804946c 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_start

70: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

其中,

51: 0804837c 24 FUNC GLOBAL DEFAULT 12 test

这行0804837c就是test()函数的起始地址,24就是test()函数的指令静态存储空间。

弱引用:只要有对象引用,他就不会被垃圾回收。

介绍之前,不了解这些概念的同学可以参考一下以下链接。

WeakMap:weakMapset(ref, realData)这边针对的是对键的弱引用。可以理解为是向对象 ref 中添加值为 realData的内容,通过ref来获取realData, 一旦不再持有对象的引用,即使你仍持有添加了该对象的 WeakMap 的引用对象,也会被垃圾回收

WeakRef:允许您保留对另一个对象的弱引用,而不会阻止被弱引用对象被GC回收。-没有很理解

看下面这个图:

对WeakMap和WeakRef新的认识

FinalizationGroup API可以注册一个回调,以便在垃圾回收器回收已注册的对象时运行。可以手动写一个回调函数用来做垃圾回收。

weakRef弱引用

参考文章: https://blogcsdnnet/howgod/article/details/103727351

注意看这个文件

sysdeps/unix/sysv/linux/syscallslist

里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。

再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。

int

__select (nfds, readfds, writefds, exceptfds, timeout)

int nfds;

fd_set readfds;

fd_set writefds;

fd_set exceptfds;

struct timeval timeout;

{

__set_errno (ENOSYS);

return -1; 

}

libc_hidden_def (__select)

stub_warning (select)

weak_alias (__select, select)

这是因为glibc并没有实现系统调用,而是调用系统调用,

更进一步,连调用系统调用都没有一个个实现,而是使用了通用的办法,

理由很简单,所有的系统调用在linux内核头文件里都能找到,

所有的系统调用参数类型就那么几种,参数个数也是有限的,

因此没有必要针对所有的系统调用一一封装,

于是就有了这个list文件,自动生成调用系统调用的函数,

如果生成失败,也就是你看到的“报错”。

符号是有强弱的,当自动生成成功的时候,“报错”的弱符号就被忽略了。

当你在glibc中找到一个系统调用的封装源码,是以下原因,

编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。

2 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。

3 针对这个系统调用做了特别的优化。

4 其它可能的原因。

具体可以留意

SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字

这两个文件是重点所在

sysdeps/unix/i386/sysdeph

sysdeps/unix/i386/sysdepS

要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了

这个问题是一个好问题,我之前也没思索过或者尝试过,

首先我们弄清楚一件事,函数声明可以放在任何头文件,实现可以放在任何实现该函数的源文件中,那么就存在一个问题:

编译时,到底优先去使用哪一个,为什么没有把标准库中的函数扩展过来;在windows下标准库被编译成了msvcr120dll(msvcr100dll,这里指release版),所以并不是扩展到代码中,而是在调用时动态链接;

而题主在其中自定义文件中实现了该函数,所以编译时找到了该函数的实现,并不会去链接dll(这应该是编译器做的一些工作,确定系统的dll需要加载哪些),所以题主的程序执行时就只有一份fputc了,并不冲突。

题主可以通过快捷键跳转声明就知道了,VS下,点选fputc实现函数按F12跳转到声明,指向的是stdioh,再按一次跳转到你自己的定义了。Qt的话使用F2。

大概就是这样子了,可追问。

常用词汇:

1、short:修饰int,短整型数据,可省略被修饰的int。

2、long:修饰int,长整型数据,可省略被修饰的int。

3、long long:修饰int,超长整型数据,可省略被修饰的int。

4、signed:修饰整型数据,有符号数据类型。

5、unsigned:修饰整型数据,无符号数据类型。

6、restrict:用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式。

7、return:用在函数体中,返回特定值(如果是void类型,则不返回函数值)。

8、continue:结束当前循环,开始下一轮循环。

9、break:跳出当前循环或switch结构。

10、goto:无条件跳转语句。

11、if:条件语句,后面不需要放分号。

12、else:条件语句否定分支(与if连用)。

13、switch:开关语句(多重分支语句)。

14、case:开关语句中的分支标记,与switch连用。

15、default:开关语句中的“其他”分支,可选。

常用函数:

1、int isalpha(int ch) 若ch是字母('A'-'Z','a'-'z'),返回非0值,否则返回0。

2、int isalnum(int ch) 若ch是字母('A'-'Z','a'-'z')或数字('0'-'9'),返回非0值,否则返回0。

3、int abs(int i) 返回整型参数i的绝对值。

4、double cabs(struct complex znum) 返回复数znum的绝对值。

5、double fabs(double x) 返回双精度参数x的绝对值。

6、long labs(long n) 返回长整型参数n的绝对值。

—C语言

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/12153409.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存