NSLog(@"测试%@",10) 做了什么?

2020-04-27  本文已影响0人  哦小小树
准备工作

如果正常打印不请求调用流程是很难看到具体调用栈的,那就先让它crash,然后再去查看调用栈。

我们知道%@是用来接Objective-C对象类型的。如果用它来接收int类型就会crash。那我们就从这里入手。


0x01 %d接收10的调用栈

int a = 10;
NSLog(@"测试%@",a);

调用栈分析

(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");
WeChat9579ff19e721db31141b5cfe99f99bf6.png

0x03 %@接收object的调用栈

// self是一个控制器ViewController
NSLog(@"测试: %@",self);

通过上图我们可以发现rcx是个指针,可以取到指针内容。
由此发现在格式转换中%@在转换过程中是需要取入参对象的地址的。


总结

NSLog(@"测试%@",10) crash的原因:访问了错误的地址信息,应该去查找一个指针的,结果查看了一个常量。

啰嗦的描述:
在后续的内存操作中,会将 10做出些调整当成一个指针,然后去取它的内容,当发现取不出内容时自然出现问题。

发散一下:
如果创建一个对象,然后把这个对象的地址转为整型赋值是否可行?

参考:
苹果官方日志打印接收类型

上一篇 下一篇

猜你喜欢

热点阅读