0

最近几天我一直在使用 Blitz 阵列包。在调试期间,我需要打印数组内容,并且 blitz 支持如下所示

std::cout<<blitz_array_name<<std::endl

我想在调试期间通过 GDB 打印数组内容。所以我为我喜欢打印的不同类型的数组编写了重载函数,如下所示

void printBlitz(blitz::Array<bool, 1> &in)
{
std::cout<<in<<std::endl;
}

void printBlitz(blitz::Array<int, 1> &in)
{
std::cout<<in<<std::endl;
}

... and so on

在 gdb 调试器上,我可以简单地调用这个函数,如下所示

(gdb) call printBlitz(blitz_array_name)
  1. 现在的问题是我正在使用多种类型的多维数组,我必须为每个数组进行重载
  2. 我无法通过 GDB 的调用功能调用模板函数 - 这也会有所帮助
  3. 我试图做类似下面的事情

(gdb) 定义 printmyvar 调用 (void)operator<<(std::cout, $arg0) print "\n" end

当我尝试如下打印数组时

(gdb) printmyvar blitz_array_name

我收到此错误“无法将函数运算符 << 解析为任何重载实例”

d)我可以定义一个宏如下

   PRINTBLITZ(myvar) std::cout<<myvar<<std::endl

但通过 GDB 我无法传递宏并执行它。

我们怎样才能简单地从GDB执行类似下面的东西

std::cout<<myvar<<std::endl

请为此问题提出任何解决方案。任何建议都非常感谢,并加速我的调试。

非常感谢您!

4

1 回答 1

1
  1. 我无法通过 GDB 的调用功能调用模板函数 - 这也会有所帮助

实际上,在尝试了一些替代方案之后,您似乎可以,但是很难正确地点它。

考虑以下代码

#include <iostream>

double tripleInput(double x) { return 3 * x; }

template <typename T>
inline T doubleInput(T x) {
    return 2 * x;
}


int main(int argc, char *argv[])
{
    std::cout << doubleInput(13) << std::endl;
    std::cout << doubleInput(1.72) << std::endl;

    std::cout << tripleInput(1.72) << std::endl;
    return 0;
}

在使用调试符号编译并使用可执行文件启动 gdb 之后,我们可以做

call tripleInput(1.5)

gdb 将返回 4.5。到目前为止,一切都很好。但是请注意,如果您编写call tri并按 TAB,gdb 将完成名称为tripleInput(double). 之后你添加(1.5),你可以运行

tripleInput(double)(1.5)

这将像以前一样工作。

现在让我们尝试使用模板doubleInput函数。那是模板的名称,但只有在您使用某种类型的模板时,编译器才会从模板生成一个函数。实际名称是doubleInput<int>,doubleInput<double>等。只有您实际使用过的版本才会在二进制文件中并且可以被 gdb 看到。

现在让我们试试

call doubleInput<double>(1.7)

和 gdb 返回3.3999999999999999. 伟大的!请注意

call doubleInput<double>(double)(1.7)

也可以。请注意

call doubleInput<int>(1.7)

返回 2,而不是 3.3999999999999999,但这是有道理的。

所以,答案是你可以调用模板的实例,只要你传递全名(使用TAB来完成名称)。

最后一点,如果我将 TripleInput 和 doubleInput 更改为通过引用而不是按值接收参数,那么它将不起作用并且我收到错误“尝试获取不在内存中的值的地址”。


  1. 现在的问题是我正在使用多种类型的多维数组,我必须为每个数组进行重载

使用前面的答案,这意味着您可以编写单个模板而不是多个实现。请务必调用一次。即使您确实实现了多个函数,您仍然需要调用它们以使链接器不会将其从二进制文件中删除。


但为了帮助调试最好的解决方案,到目前为止,是使用 gdb 的 Python API 为bliz::Array类型编写自定义的漂亮打印机。blitz::Array如果您有漂亮的闪电战类型打印机,那么您只需要看到p variable_name. 即使您从核心文件进行调试(如果没有劣质运行,您无法调用函数),这也将始终有效。

不幸的是,我找不到任何用于 blitz 的漂亮打印机的现有实现,这意味着您必须自己编写它。

我没有 blitz 的经验,但我经常使用armadillo,它是一个用于线性代数和科学计算的 C++ 库,并且我为犰狳类型编写了漂亮的打印机。如果您好奇,请参阅此答案此存储库。

编写漂亮的打印机需要您对编写漂亮打印机的类型存储其数据的方式有所了解。您需要阅读gdb 的相关文档,但最好的方法是查看漂亮打印机的其他实现。至少我是这样做的。

于 2020-05-08T18:42:31.777 回答