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



我有一个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) $0 = 56

我正在加载以下库:

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

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

编辑:我还应该补充一点,xcode中的变量资源管理器正确地将I的值显示为整数。

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

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

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

(lldb) expr @import Darwin

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

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

OTOH,如果lldb这样做是因为调试信息记录了你代码的某个部分导入了这个模块,你可以通过放置来关闭行为

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

在~/.lldinit中,然后重新启动调试会话。

顺便说一句,p命令(或p是其别名的expression命令)使用语言并在当前帧的上下文中,将您提供的文本作为正则表达式进行评估,并尽可能多地访问lldb所能提供的符号、定义等。大多数用户还希望能够访问在当前帧中可能不直接可见的类信息,因此它倾向于尽可能广泛地寻找符号和类型来实现这一点。

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

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

因此,除非你真的需要运行一个表达式(例如访问一个计算属性或调用另一个函数),否则v会更快,而且因为它的实现更简单、更直接,所以它比p发生细微故障的几率更小。

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

我绝对没有一个宏将I定义为复杂变量。

看起来lldb不知怎么搞混了,这不是代码的问题,但如果没有MRE,就很难说了。

我在xcode中运行的那个,我用默认的xcode工具编译。我在命令行中运行的那个,我使用gcc。不知怎么的,这就是区别吗?

xcode使用";苹果叮当"据我所知,(一个旧的自定义版本)默认使用libc++。gcc完全不同,它甚至可能不使用libc++。

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

xcode是否包含了比我要求的更多的库?

我不这么认为,因为程序可以工作,Xcode将值显示为整数。

为什么会发生这种情况,我该如何预防?

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

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

此外,如前所述,复数I在<complex.h>:

要构造复数,需要一种方法来表示虚数数字的一部分。虚数没有标准的表示法浮点常数。相反,complex.h定义了两个宏可以用来创建复数。

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

GNU实现参考此处

包括这个头文件(或来自您的环境的类似文件),无需自己定义

最新更新