首页 > 解决方案 > 包含双数组的 GDB 漂亮打印自定义类型

问题描述

尝试为 GDB 编写一个 Python 扩展,它能够漂亮地打印以下 C++ 类:

class Vector {
  double* myElements;
  unsigned int length;
}

漂亮的打印输出应该在哪里,例如。{0.1, 0.2, 0.3}其中数组myElements的长度为length

在 gdb 中,我可以简单地做,*myVec.myElements@myVec.length但是我想创建等效的 Python 漂亮打印。

我目前的尝试如下:

class VectorPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        length = self.val['length']
        elmts = self.val['myElements']
        result = []
        for i in range(0, length):
            result.append(elmts[i])

        return str(result)


class FailPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        return "Value: " + str(self.val.type)

def lookup_type(val):
    if(str(val.type) == 'Vector'):
        return VectorPrinter(val)
    return FailPrinter(val)

gdb.pretty_printers.append(lookup_type)

然而,这只是输出:

$1 = [<gdb.Value object at 0x000000000367d470>, <gdb.Value object at 0x000000000367d4b0>, ...,
 <gdb.Value object at 0x000000000367d8f0>, <gdb.Value object at 0x000000000367d930>]

标签: pythonc++gdb

解决方案


当您的类型是某种“数组”时,最好保持to_string方法简单(不处理元素)并有一个children方法返回一个检索元素的生成器,以及一个display_hint方法。此display_hint方法必须返回字符串“array”,以指示 gdb 应使用该children方法获取元素。

to_string方法可以简单到只返回一个简单的字符串,例如“vector”,但我发现包含向量的大小很有用。

我为您的班级创建了以下漂亮的打印机

class VectorPrinter:
    def __init__(self, val):
        self.val = val
        self.length = int(val['length'])
        self.mem = self.val['myElements']

    def to_string(self):
        return f"Vector with {self.length} elements"

    def next_element(self):
        for i in range(self.length):
            yield str(i), (self.mem + i).dereference()

    def children(self):
        return self.next_element()

    def display_hint(self):
        return "array"

请注意,该next_element方法实际上是一个生成器,因为它使用yield而不是返回。

但是,当我尝试使用这台漂亮的打印机时,每个元素都被打印为Value: double,. 问题是因为FailPrinter. 您注册漂亮打印机的方式意味着除了 Vector 类之外,其他所有内容都使用 打印FailPrinter,包括每个单独的元素。您真的不需要(或想要)“失败”打印机。

因此,只需使用我提供的课程并注册即可

def lookup_type(val):
    if(str(val.type) == 'Vector'):
        return VectorPrinter(val)

gdb.pretty_printers.append(lookup_type)

让我们看看这台漂亮的打印机正在运行。考虑下面的 main.cpp 文件


class Vector {
public:
    double* myElements;
    unsigned int length;

public:
    Vector(unsigned int length) : length(length) {
        myElements = new double[length];
        for (unsigned int i = 0; i < length; i++) {
            myElements[i] = i;
        }
    }

    ~Vector() {
        delete[] myElements;
    }
};

int main(int argc, char *argv[])
{
    Vector v(10);
    return 0;
}

如果我们v在 gdb 中打印,我们会得到

漂亮的打印矢量 v


注意:如果您有兴趣,我已经为犰狳库中的向量、矩阵和立方体类以及std::complex. 这些漂亮的打印机可以在这里找到。查看代码可能会帮助您创建其他漂亮的打印机。


推荐阅读