两种GDB漂亮打印机注册方式输出差异原因及冗余消除方法
GDB两种漂亮打印机注册方式的输出差异问题
C++测试代码
struct number { int n; }; int main() { number n{5}; const number & ref = n; }
两种GDB漂亮打印机实现
Printer1(旧注册方式)
class Printer: def __init__(self, val): self.val = val def to_string(self): return str(self.val["n"]) def matcher(val): lookup_tag = val.type.tag if lookup_tag is None: return None if lookup_tag == "number": return Printer(val) gdb.pretty_printers.append(matcher)
Printer2(使用RegexpCollectionPrettyPrinter的新注册方式)
class Printer: def __init__(self, val): self.val = val def to_string(self): return str(self.val["n"]) def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter("num") pp.add_printer("num", "^number$", Printer) return pp gdb.printing.register_pretty_printer(None, build_pretty_printer())
输出差异
使用Printer1打印ref时,GDB输出:
$1 = (const number &) @0x7fffffffe0b8: 5
使用Printer2打印ref时,GDB输出:
$1 = 5
问题
两种方式的Printer实现完全一致,仅注册方式不同。请问为何两种注册方式会导致输出差异?Printer1为何会打印(const number &) @0x7fffffffe0b8?如何消除该冗余内容?
解答
差异原因
- 旧注册方式的局限性:直接将matcher追加到
gdb.pretty_printers的方式,只会匹配传入的原始值类型。当打印引用类型const number &时,GDB认为当前值的类型是引用而非底层的number结构体,因此会先输出引用的类型和内存地址,再调用打印机打印引用指向的对象内容,最终呈现带冗余信息的输出。 - 新注册方式的自动处理:
RegexpCollectionPrettyPrinter是GDB官方封装的工具,内部会自动处理引用、指针等包装类型——它会先自动解引用,提取到底层的number对象再应用打印机,因此不会输出引用的额外信息。
消除Printer1的冗余内容
修改matcher函数,提前处理引用类型,手动解引用得到底层对象:
class Printer: def __init__(self, val): self.val = val def to_string(self): return str(self.val["n"]) def matcher(val): # 处理引用类型,手动解引用 val_type = val.type if val_type.code == gdb.TYPE_CODE_REF: val = val.referenced_value() val_type = val.type # 可选:添加指针类型处理,支持指针打印 elif val_type.code == gdb.TYPE_CODE_PTR: val = val.dereference() val_type = val.type lookup_tag = val_type.tag if lookup_tag is None: return None if lookup_tag == "number": return Printer(val) gdb.pretty_printers.append(matcher)
修改后,打印ref时会和Printer2输出一致,仅显示5。
内容的提问来源于stack exchange,提问作者user13840624
相关产品推荐
相关产品推荐

