无法在 Xcode 调试器中按名称解析枚举值

Cannot resolve enum values by name in Xcode debugger

在整个项目中使用的全局头文件中使用了枚举类型定义,在 Xcode.

中使用 lldb 时,我无法按名称引用各个枚举值

例如,如果我在枚举类型可用的任何地方的断点处停止,并且我尝试在 Xcode(例如 (lldb) p (int)EnumConstant)的 lldb 提示符处评估某些内容,lldb 会抱怨:

error: use of undeclared identifier 'EnumConstant'

此外,如果我尝试在条件中使用枚举常量设置条件断点(例如,右键单击 Xcode 中的断点 > 编辑断点... > 条件:EnumConstant == someLocalVar),然后 Xcode 每次尝试在该断点评估该条件时都会抱怨:

Stopped due to an error evaluating condition of breakpoint 1.1: "EnumConstant == someLocalVar"
Couldn't parse conditional expression:
error: use of undeclared identifier 'EnumConstant'
当我开始在 "Edit Breakpoint..." window 中输入名称时,

Xcode 的代码完成弹出窗口甚至解决了对枚举常量的建议,因此 Xcode 本身不会解决它有问题。

有没有我可以在 lldb 或 Xcode 中设置的选项,以便 lldb 在 编译后 维护枚举标识符?我假设枚举常量在编译期间被转换为它们的序数值,导致可执行文件丢弃标识符,但这只是我天真的猜测。

当我在 Linux 或 Cygwin 中的简单 GNU C 程序中使用等效代码时(显然减去 class 定义),但使用 gcc/gdb 而不是 Xcode/lldb,我没有这些问题。它能够毫无问题地解析枚举值。


我创建了一个小型 Xcode iPhone 项目来证明我的意思。在 ViewController.m 上下文中使用下面的任何 enum_t 常量(for 循环是演示的好地方)将产生相同的结果。

ViewController.h:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

typedef enum
{
    eZero, eOne, eTwo, eCOUNT
}
enum_t;

extern NSString const * const ENUM_STR[];

@end

ViewController.m:

#import "ViewController.h"

@implementation ViewController

NSString const * const ENUM_STR[eCOUNT] = { @"eZero", @"eOne", @"eTwo" };

- (void)viewDidLoad
{
    [super viewDidLoad];

    for (enum_t value = eZero; value < eCOUNT; ++value)
    {
        NSLog(@"%-8@ = %d", ENUM_STR[value], value);
    }
}

@end

这是一个关于如何构建枚举的名称-> 调试信息查找加速器表的错误(相当长的时间)。虽然列出了枚举类型,但没有列出枚举值。这样做肯定是为了节省输出调试信息的大小——调试信息很快就会变得相当大,因此添加更多信息的成本和更多信息的效用之间一直存在紧张关系。目前这个还没有上升到包容的程度。

无论如何,通过 "all debug information for anything with a name that matches 'eZero'" 进行搜索即使对于体面大小的项目也非常慢,并且对于大型项目来说真的很糟糕。所以 lldb 总是使用这些 name->Debug Info 表来进行第一级访问。

因为加速器表确实包含按名称的枚举类型(对您来说更重要的是按名称的类型定义),解决方法是:

(lldb) 表达式 enum_t::eZero (整数) $0 = 0

当然,如果您有真正的匿名枚举,那么在将此信息添加到加速表之前,您就很不走运了。

顺便说一句,调试器控制台 window 中的 Xcode 符号完成是使用 Xcode SourceKit 索引器完成的,而不是 lldb。因此 Xcode 提供的补全并不反映 lldb 对该程序的了解。

BBTW,gdb 不使用编译器制作的加速器表(在新的 DWARF 5 标准之前,这些是 Apple 的扩展),而是通过扫描调试信息手动构建索引。这使他们可以索引调试器认为最好的任何内容。 OTOH,它会使大型项目的调试器启动速度变慢。