xcode 中的 lldb 检测到称为 I 的整数是一个复数

lldb in xcode detects integer called I to be a complex number

我有一个 C 代码,其中声明并初始化了一个 int I。当我在 xcode 中调试时,如果我尝试打印 I 的值,xcode 会尝试找到一个复数:

(lldb) p I
error: <lldb wrapper prefix>:43:31: expected unqualified-id
using $__lldb_local_vars::I;
                          ^
<user expression 3>:1760:11: expanded from here
#define I _Complex_I
      ^
<user expression 3>:7162:20: expanded from here
#define _Complex_I ( __extension__ 1.0iF )

当我在不使用 xcode 的命令行中尝试相同的操作(在代码中的同一行停止)时,它工作正常:

(lldb) p I
(int) [=12=] = 56

我正在加载以下库:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

这甚至不应该包含复数,不是吗?我绝对没有将 I 定义为复杂变量的宏。我在 xcode 运行 中使用默认的 xcode 工具进行编译。我在命令行中的运行,我使用gcc。这就是区别吗? xcode 包含的库是否比我要求的多?为什么会发生这种情况,我该如何预防?

编辑:我还应该补充一点,xcode 中的变量 explorer 正确显示 I 的值,作为整数。

I definitely don't have a macro that defines I to be the complex variable.

看起来 lldb 不知何故变得混乱,这不是您的代码的问题,但如果没有 MRE,则很难说。

The one I run in xcode, I compile with the default xcode tools. The one I run in the command line, I use gcc. Is this the difference, somehow?

据我所知,

xcode 默认情况下将“Apple clang”(旧的自定义版本)与 libc++ 一起使用。 gcc 完全不同,它甚至可能不会使用 libc++。

话虽如此,由于 xcode 将变量显示为整数,而 lldb 却没有,因此看起来好像发生了其他事情。

Is xcode including more libraries than I ask it to?

我不这么认为,因为程序可以运行并且 Xcode 将值显示为整数。

Why is this happening and how can I prevent it?

很难说,因为它是一个闭源工具。尝试做一个MRE。它通常有助于调试问题和找到解决方法。

根据定义,复数不能简单地定义为 int

此外,如前所述,复数 I 中定义:

To construct complex numbers you need a way to indicate the imaginary part of a number. There is no standard notation for an imaginary floating point constant. Instead, complex.h defines two macros that can be used to create complex numbers.

Macro: const float complex _Complex_I

    This macro is a representation of the complex number “0+1i”. Multiplying a real floating-point value by _Complex_I gives a complex number whose value is purely imaginary. You can use this to construct complex constants:

    3.0 + 4.0i = 3.0 + 4.0 * _Complex_I

    Note that _Complex_I * _Complex_I has the value -1, but the type of that value is complex. 

_Complex_I is a bit of a mouthful. complex.h also defines a shorter name for the same constant.

Macro: const float complex I

    This macro has exactly the same value as _Complex_I. Most of the time it is preferable. However, it causes problems if you want to use the identifier I for something else. You can safely write

    #include <complex.h>
    #undef I

Reference here for GNU implementation

包含此 header 文件(或您环境中的类似文件),无需自己定义它

$__lldb_local_vars 是一个人工命名空间,lldb 在编译前将其注入到它为您的表达式设置的包装器中,以便 clang 可以找到框架的局部变量及其类型。这个问题正如其他人所指出的那样,因为我们在编译表达式时也 运行 预处理器,并且您的变量名与表达式上下文中的预处理器符号冲突。

通常情况下,调试信息根本不记录宏,因此您在代码中使用时看不到 I 的 complex.h 版本。相反,您看到 I 宏是因为某些原因导致 Darwin 模块被导入到 lldb 的表达式上下文中。

这可以通过两种方式发生,要么是因为您明确要求 运行ning:

(lldb) expr @import Darwin

或者因为您使用 -fmodules 构建了此程序,并且您的代码通过插入上述语句导入了 Darwin 模块。

手动执行此操作是一种常见的技巧,可以显式地使模块中的#defines 对表达式解析器可见。由于导致问题的是宏的可见性,因此如果您希望此表达式成功,则必须停止这样做。

OTOH,如果 lldb 这样做是因为调试信息记录了您的某些代码导入了该模块,您可以通过以下方式关闭该行为:

settings set target.auto-import-clang-modules 0

在您的 ~/.lldbinit 中并重新启动调试会话。

顺便说一句,p 命令(或 p 是别名的 expression 命令)使用语言和在当前帧的上下文,以及 lldb 可以提供的对符号、定义等的尽可能多的访问。大多数用户还希望能够访问在当前帧中可能无法直接看到的 class 信息,因此它倾向于尽可能广泛地寻找符号和类型以实现这一点。

这是一个非常强大的功能,但正如您所看到的,有时希望为表达式提供这种广泛的访问权限会导致定义冲突。无论如何,它比仅查看局部变量所需的功能要强大得多。

lldb 有另一个命令:frame var(方便的别名 v)它通过直接访问调试信息指向的内存并使用调试信息中的类型来显示局部变量值.它支持子元素引用的 C-like 语法的有限子集;您可以使用 * 取消引用,.-> 如果变量是数组 [0] 等...

所以除非你真的需要 运行 一个表达式(例如访问计算的 属性 或调用另一个函数),v 会更快,因为它的实现是比 p.

更简单、更直接,出现细微故障的可能性更小

如果您还想访问某些 ObjC 或 Swift 局部变量的对象定义,命令 voframe var -O 将获取它找到的局部变量的描述v 方法。