准备工作
如果正常打印不请求调用流程是很难看到具体调用栈的,那就先让它crash
,然后再去查看调用栈。
我们知道%@
是用来接Objective-C
对象类型的。如果用它来接收int
类型就会crash
。那我们就从这里入手。
0x01 %d
接收10
的调用栈
- 测试代码:
int a = 10;
NSLog(@"测试%@",a);
-
WeChat5d3773466930a21378cddf74cb3675d3.pngcrash
截图
-
crash
分析
调用栈分析
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
* frame #0: 0x00007fff50b52d93 libobjc.A.dylib`objc_opt_respondsToSelector + 13
frame #1: 0x00007fff2593f4ea Foundation`_NSDescriptionWithStringProxyFunc + 41
frame #2: 0x00007fff23dc69c7 CoreFoundation`__CFStringAppendFormatCore + 10935
frame #3: 0x00007fff23dc8cf5 CoreFoundation`_CFStringCreateWithFormatAndArgumentsAux2 + 133
frame #4: 0x00007fff51bc3e08 libsystem_trace.dylib`_os_log_impl_dynamic + 228
frame #5: 0x00007fff51bc446b libsystem_trace.dylib`_os_log_with_args_impl + 562
frame #6: 0x00007fff23e2085b CoreFoundation`_CFLogvEx3 + 235
frame #7: 0x00007fff25924e40 Foundation`_NSLogv + 104
frame #8: 0x00007fff25924ed8 Foundation`NSLog + 132
通过调用栈我们可以发现,是因为访问了错误的地址address=0x1
导致crash
的。
crash崩溃点可以发现:
-> 0x7fff50b52d93 <+13>: movq (%rcx), %rdx
汇编解析:
rcx这个寄存器存放的是个地址,将这个地址中的内容取出放到rdx这个寄存器。
打印寄存器
lldb) register read
General Purpose Registers:
rax = 0x00007fff51fbad08
rbx = 0x00007ffee180ef00
rcx = 0x0000000000000001
rdx = 0x00007fff80640e90 @"%@NSCONTEXT"
rdi = 0x0000000000000001
可以发现:
rcx
地址太小,根本不是个指针。故而我们也不可能从里面取到一个内容.
0x02 %@
接收string
的调用栈
- 测试代码
NSLog(@"测试: %@",@"hello");
-
符号断点截图:
WeChatecc62b3d7e67cfcdf3d40e4534bbcb73.png
0x03 %@
接收object
的调用栈
- 测试代码
// self是一个控制器ViewController
NSLog(@"测试: %@",self);
-
符号断点截图
WeChat22d2b7109294087c9713a7596d677242.png
通过上图我们可以发现rcx
是个指针,可以取到指针内容。
由此发现在格式转换中%@
在转换过程中是需要取入参对象的地址的。
总结
NSLog(@"测试%@",10)
crash
的原因:访问了错误的地址信息,应该去查找一个指针的,结果查看了一个常量。
啰嗦的描述:
在后续的内存操作中,会将 10
做出些调整当成一个指针,然后去取它的内容,当发现取不出内容时自然出现问题。
发散一下:
如果创建一个对象,然后把这个对象的地址转为整型赋值是否可行?
参考:
苹果官方日志打印接收类型
网友评论