Xcode 的 LLDB 调试器中 "p" 和 "po" 有什么区别?
What's the difference between "p" and "po" in Xcode's LLDB debugger?
示例:我在我的旧项目和一个新的、清晰的项目中写了以下字符串:
UIInterfaceOrientation k = [UIApplication sharedApplication].statusBarOrientation;
控制台 input/output 一个明确的项目:
(lldb) po k
UIInterfaceOrientationLandscapeLeft
如果我写“po k”——无用整数列表,那么在我的旧项目中会出现一些糟糕的情况。
此外,我无法打印新项目中的大部分对象。
UIInterfaceOrientation
不是 (Objective-C) 对象,而是一个整数 (enum:NSInteger
)。你根本不应该使用 po
(print object)。
Strip debug symbols during copy
在大多数答案中,他们建议将优化设置为 "none",但忘记了应将此选项设置为 NO(至少对于调试配置)。
我不知道你的情况是怎么回事,只是为了让人们清楚 po
和 p
之间的区别:
p
命令(a.k.a.expr --
)获取给定的参数,将它们编译为就好像它们是在当前帧的上下文中编写的源代码表达式一样, 执行结果 - 如果可能的话,通过 运行 编译结果的解释器,或者通过 JITing 编译结果,将其插入目标程序,然后 运行 它在那里。然后打印评估结果。
po
命令(a.k.a。expr --O --
)执行 p
执行的所有操作,但不打印结果,如果结果是指向ObjC 对象,它调用该对象的 "description" 方法,并打印该方法返回的字符串 (*)。同样,如果结果是一个 CF 对象,它将调用 CFShow 并打印结果。如果这两次尝试都失败了,它会继续打印结果,就像 p
那样。
所以 po
很像 p
。但是如果你在它实际上不是对象的东西上使用 po
,你会得到一些奇怪的结果。例如,ObjC 有一个优化(标记指针),它在对象指针中表示某些对象(例如 NSNumbers)的内容。没有 "real" 对象,只有熟指针。因此,如果您尝试 po
一个恰好看起来像标记指针的整数,您将得到一些可能不相关的 ObjC 对象的描述,而不是整数的值。
当然,po
做了更多的工作,所以除非你真的想要某个对象对自身的描述,否则 p
效率更高。
- 实际上,它会调用 debugDescription(如果存在),如果不存在则回退到描述...
这是参考 Jim Ingham 所说的。输入 "p " 而不是 "po "。当我这样做时 Xcode 显示正确的信息。试试看。
似乎区别在于 lldb/gdb 调试器。 iOS 项目使调试器更可用的唯一方法是 expr @import UIKit
。但它可能不适用于较旧的 xcode 版本并且...您需要在每次重新启动后在控制台中输入此字符串。使其自动化的唯一方法是使用此表达式添加一个额外的断点。
p
= 打印
po
= 打印对象
p
打印原始变量的值或引用的值
po
尝试为该对象调用 -description 并打印返回的字符串
p prints value of primitive variable or value of a reference
po try to call -description for that object and print returned string
There is also **v command** in lldb. Explaining using example.
protocol Activity {}
struct Trip: Activity {
var name: String
var destinations: [String]
}
let cruise: Activity = Trip(...)
Using v command
(lldb) v cruise.name
(string) cruise.name = "print name"
//As it uses dynamic resolution
Using p command
(lldb) p cruise.name
//execution interrupted
- 使用 po、p 和 v 打印变量
- po 最终编译并执行了两次,一次是计算表达式,另一次是获取对象描述。
- v 根本无法编译:无法计算任何表达式,但允许 属性 访问并进行递归动态类型解析,因此每个 属性 都被视为实际的运行时类型。
对于有兴趣了解更多信息的人:https://developer.apple.com/videos/play/wwdc2019/429/
将此添加为可见性的答案,还解释了每个调试命令的功能
po
尝试将您要打印的内容视为一个对象。在很多情况下它类似于p
,但也有一些情况会出现差异。
查看差异的最简单方法:比较 p 0
和 po 0
的输出。
(lldb) p 0
(int) = 0
(lldb) po 0
<nil>
示例:我在我的旧项目和一个新的、清晰的项目中写了以下字符串:
UIInterfaceOrientation k = [UIApplication sharedApplication].statusBarOrientation;
控制台 input/output 一个明确的项目:
(lldb) po k
UIInterfaceOrientationLandscapeLeft
如果我写“po k”——无用整数列表,那么在我的旧项目中会出现一些糟糕的情况。
此外,我无法打印新项目中的大部分对象。
UIInterfaceOrientation
不是 (Objective-C) 对象,而是一个整数 (enum:NSInteger
)。你根本不应该使用 po
(print object)。
Strip debug symbols during copy
在大多数答案中,他们建议将优化设置为 "none",但忘记了应将此选项设置为 NO(至少对于调试配置)。
我不知道你的情况是怎么回事,只是为了让人们清楚 po
和 p
之间的区别:
p
命令(a.k.a.expr --
)获取给定的参数,将它们编译为就好像它们是在当前帧的上下文中编写的源代码表达式一样, 执行结果 - 如果可能的话,通过 运行 编译结果的解释器,或者通过 JITing 编译结果,将其插入目标程序,然后 运行 它在那里。然后打印评估结果。
po
命令(a.k.a。expr --O --
)执行 p
执行的所有操作,但不打印结果,如果结果是指向ObjC 对象,它调用该对象的 "description" 方法,并打印该方法返回的字符串 (*)。同样,如果结果是一个 CF 对象,它将调用 CFShow 并打印结果。如果这两次尝试都失败了,它会继续打印结果,就像 p
那样。
所以 po
很像 p
。但是如果你在它实际上不是对象的东西上使用 po
,你会得到一些奇怪的结果。例如,ObjC 有一个优化(标记指针),它在对象指针中表示某些对象(例如 NSNumbers)的内容。没有 "real" 对象,只有熟指针。因此,如果您尝试 po
一个恰好看起来像标记指针的整数,您将得到一些可能不相关的 ObjC 对象的描述,而不是整数的值。
当然,po
做了更多的工作,所以除非你真的想要某个对象对自身的描述,否则 p
效率更高。
- 实际上,它会调用 debugDescription(如果存在),如果不存在则回退到描述...
这是参考 Jim Ingham 所说的。输入 "p " 而不是 "po "。当我这样做时 Xcode 显示正确的信息。试试看。
似乎区别在于 lldb/gdb 调试器。 iOS 项目使调试器更可用的唯一方法是 expr @import UIKit
。但它可能不适用于较旧的 xcode 版本并且...您需要在每次重新启动后在控制台中输入此字符串。使其自动化的唯一方法是使用此表达式添加一个额外的断点。
p
= 打印
po
= 打印对象
p
打印原始变量的值或引用的值
po
尝试为该对象调用 -description 并打印返回的字符串
p prints value of primitive variable or value of a reference
po try to call -description for that object and print returned string
There is also **v command** in lldb. Explaining using example.
protocol Activity {}
struct Trip: Activity {
var name: String
var destinations: [String]
}
let cruise: Activity = Trip(...)
Using v command
(lldb) v cruise.name
(string) cruise.name = "print name"
//As it uses dynamic resolution
Using p command
(lldb) p cruise.name
//execution interrupted
- 使用 po、p 和 v 打印变量
- po 最终编译并执行了两次,一次是计算表达式,另一次是获取对象描述。
- v 根本无法编译:无法计算任何表达式,但允许 属性 访问并进行递归动态类型解析,因此每个 属性 都被视为实际的运行时类型。
对于有兴趣了解更多信息的人:https://developer.apple.com/videos/play/wwdc2019/429/
将此添加为可见性的答案,还解释了每个调试命令的功能
po
尝试将您要打印的内容视为一个对象。在很多情况下它类似于p
,但也有一些情况会出现差异。
查看差异的最简单方法:比较 p 0
和 po 0
的输出。
(lldb) p 0
(int) = 0
(lldb) po 0
<nil>