问题描述
我有一个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时,它运行良好:
@H_404_6@(lldb) p I
(int) $0 = 56
我正在加载以下库:
@H_404_6@#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
哪个甚至不应该包含复数,对吗?我绝对没有将I
定义为复杂变量的宏。我在xcode中运行的那个,我使用默认的xcode工具进行编译。我在命令行中运行的那个我使用gcc
。这有什么区别吗? xcode是否包含比我要求的更多的库?为什么会发生这种情况,我该如何预防呢?
编辑:我还应该补充一点,xcode中的变量资源管理器以整数形式正确显示I
的值。
解决方法
我绝对没有一个宏定义我为复杂变量。
看起来lldb有点困惑,这与您的代码无关,但是没有MRE,很难说。
据我所知,我在xcode中运行的那个,我使用默认的xcode工具进行编译。我在命令行中运行的那个我使用gcc。这有什么区别吗?
xcode默认在libc ++中使用“ Apple clang”(旧的自定义版本)。 gcc
完全不同,甚至可能没有使用libc ++。
话虽如此,由于xcode将变量显示为整数,而lldb却没有,因此看起来好像发生了其他事情。
xcode是否包含比我要求的更多的库?
我不认为如此,因为该程序可以运行,并且Xcode将值显示为整数。
为什么会这样?我该如何预防?
很难说,因为它是一个封闭的源代码工具。尝试制作MRE。通常,它有助于调试问题并找到解决方法。
,根据定义,复数不能简单地定义为int
此外,如上所述,在{complex.h>中定义了复数I
:
要构造复数,您需要一种表示虚数的方法 数字的一部分。没有虚构的标准符号 浮点常数。相反,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
Reference here for GNU implementation
包括此header文件(或您环境中的类似文件),而无需自己定义
, $__lldb_local_vars
是一个人工命名空间,lldb会在编译之前将lldb注入为其设置的包装中,以便clang可以找到框架的局部变量及其类型。正如其他人指出的那样,问题来了,因为我们在编译表达式时也会运行预处理器,并且您的变量名与表达式上下文中的预处理器符号冲突。
通常,调试信息根本不会记录宏,因此您自己在代码中的使用不会看到I
的complex.h版本。相反,您看到的是I
宏,因为某些原因导致Darwin模块被导入到lldb的表达式上下文中。
这可以通过两种方式发生,一种是因为您通过运行来明确要求它:
(lldb) expr @import Darwin
或者是因为您使用-fmodules
来构建了该程序,并且您的代码通过插入上述语句而导入了Darwin模块。
手工执行此操作是一个显式的常见技巧,可以使表达式解析器可以看到模块中的#define。由于导致问题的原因是宏的可见性,所以如果您希望此表达式成功,则必须停止这样做。
OTOH,如果lldb这样做是因为调试信息记录了您的代码的某些部分已导入了此模块,则可以通过以下方式关闭行为:
settings set target.auto-import-clang-modules 0
〜/ .lldbinit中,然后重新启动调试会话。
顺便说一句,p
命令(或expression
作为别名的p
命令)使用以下语言和在上下文中评估您提供的作为正则表达式的文本当前帧,具有对lldb可以提供的对符号的尽可能多的访问权限。大多数用户还希望能够访问在当前框架中可能不直接可见的类信息,因此,为了实现此目的,它倾向于尽可能广泛地寻找符号和类型的网。
这是一个非常强大的功能,但是正如您看到的那样,有时对表达式提供这种广泛访问的愿望可能会导致定义冲突。而且无论如何,它比查看局部变量要强大得多。
lldb还有另一个命令:frame var
(方便的别名v
),该命令通过直接访问调试信息所指向的内存并使用调试信息中的类型来显示它来打印局部变量值。它支持有限的类C语法子集供子元素引用。您可以使用*
解引用,.
或->
,如果变量是数组[0]
等...
因此,除非您确实需要运行表达式(例如,访问计算的属性或调用另一个函数),否则v
会更快,并且由于其实现更简单,更直接,因此机会更少比p
细微的故障。
如果您还想访问某些ObjC或Swift局部变量的对象定义,则命令vo
或frame var -O
将获取使用v
找到的局部变量的描述。方法。