使用 gdb 调试 C++ 模板
debug c++ template with gdb
当我在带有模板的函数内部进行调试时,
如何知道当前函数使用的模板类型?
我试过了p T
。它说 gdb 无法打印类型。
如何打破特定模板类型?
假设函数 foo<T>(...)
有两种可能的形式, foo<int>(...)
和 foo<long>(...)
。如何设置断点,以便 gdb 仅在第一个使用 int
的断点处暂停,而不是在第二个使用 long
的断点处暂停?
编辑:如果断点可以按行号设置就好了。这有很多很好的理由,例如。函数的初始部分可能需要很长时间才能 运行,我希望调试的地方可能在 if
语句中等
您可以使用 ptype
而不是 p
来打印类型。使用足够新的(几年前的)g++ 和 gdb,这将起作用。
考虑这个来源:
#include <iostream>
template<typename T>
struct S
{
S(T t)
{
std::cout << t;
}
};
int main()
{
S<const char*> s2("hello");
S<int> s1(23);
return 0;
}
在这里我可以进入 s2
的构造函数并查看 T
:
(gdb) ptype T
type = const char *
查看当前帧:
(gdb) frame
#0 S<char const*>::S (this=0x7fffffffe35f, t=0x400940 "hello") at q.cc:8
8 std::cout << t;
我可以使用此处给出的函数名称设置断点:
(gdb) b S<const char *>::S
Breakpoint 2 at 0x40087a: file q.cc, line 8.
要为所有实例设置断点,请使用:
gdb> rbreak Foo<.*>
只在已知实例上设置断点
gdb> break Foo<int>
您也可以使用 rbreak Foo<int>
但是使用调用 计算正则表达式是没有意义的,但是您给出 none :-)
示例代码:
#include <iostream>
#include <string>
template < typename T>
T Foo(T t) { return t; }
int main()
{
std::cout << Foo<int>(1) << std::endl;
std::cout << Foo<std::string>("Hallo") << std::endl;
}
使用调试信息简单编译:
g++ main.cpp -g -o go
运行 gdb:
gdb go
并测试:
gdb> rbreak Foo<int>
gdb> run
gdb> backtrace
gdb> cont
如您所见:只有一个模板实例受到影响。
在回溯中,您可以看到调用了哪个模板实例:
#0 Foo<int> (t=1) at main.cpp:5
#1 0x0000000000400b69 in main () at main.cpp:9
如您所见,这里是Foo<int>
。
回复评论:
“有没有办法在特定行的特定已知实例中放置断点?”
是的!
gdb> break main:692
gdb> info break
这将return类似于
Num Type Disp Enb Address What
5 breakpoint keep y <MULTIPLE>
5.1 y 0x00000000004026db in Foo<int>(int) at main.cpp:692
5.2 y 0x00000000004027a6 in Foo<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) at main.cpp:692
(gdb)
现在您可以禁用特定实例:
gdb> disable 5.2
您不能删除特定的“子断点”。但是禁用正是您所需要的。如果您愿意,您还可以提供一系列实例,例如:
gdb> disable 5.1-2
当我在带有模板的函数内部进行调试时,
如何知道当前函数使用的模板类型?
我试过了
p T
。它说 gdb 无法打印类型。如何打破特定模板类型?
假设函数
foo<T>(...)
有两种可能的形式,foo<int>(...)
和foo<long>(...)
。如何设置断点,以便 gdb 仅在第一个使用int
的断点处暂停,而不是在第二个使用long
的断点处暂停?
编辑:如果断点可以按行号设置就好了。这有很多很好的理由,例如。函数的初始部分可能需要很长时间才能 运行,我希望调试的地方可能在 if
语句中等
您可以使用 ptype
而不是 p
来打印类型。使用足够新的(几年前的)g++ 和 gdb,这将起作用。
考虑这个来源:
#include <iostream>
template<typename T>
struct S
{
S(T t)
{
std::cout << t;
}
};
int main()
{
S<const char*> s2("hello");
S<int> s1(23);
return 0;
}
在这里我可以进入 s2
的构造函数并查看 T
:
(gdb) ptype T
type = const char *
查看当前帧:
(gdb) frame
#0 S<char const*>::S (this=0x7fffffffe35f, t=0x400940 "hello") at q.cc:8
8 std::cout << t;
我可以使用此处给出的函数名称设置断点:
(gdb) b S<const char *>::S
Breakpoint 2 at 0x40087a: file q.cc, line 8.
要为所有实例设置断点,请使用:
gdb> rbreak Foo<.*>
只在已知实例上设置断点
gdb> break Foo<int>
您也可以使用 rbreak Foo<int>
但是使用调用 计算正则表达式是没有意义的,但是您给出 none :-)
示例代码:
#include <iostream>
#include <string>
template < typename T>
T Foo(T t) { return t; }
int main()
{
std::cout << Foo<int>(1) << std::endl;
std::cout << Foo<std::string>("Hallo") << std::endl;
}
使用调试信息简单编译:
g++ main.cpp -g -o go
运行 gdb:
gdb go
并测试:
gdb> rbreak Foo<int>
gdb> run
gdb> backtrace
gdb> cont
如您所见:只有一个模板实例受到影响。
在回溯中,您可以看到调用了哪个模板实例:
#0 Foo<int> (t=1) at main.cpp:5
#1 0x0000000000400b69 in main () at main.cpp:9
如您所见,这里是Foo<int>
。
回复评论: “有没有办法在特定行的特定已知实例中放置断点?”
是的!
gdb> break main:692
gdb> info break
这将return类似于
Num Type Disp Enb Address What
5 breakpoint keep y <MULTIPLE>
5.1 y 0x00000000004026db in Foo<int>(int) at main.cpp:692
5.2 y 0x00000000004027a6 in Foo<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) at main.cpp:692
(gdb)
现在您可以禁用特定实例:
gdb> disable 5.2
您不能删除特定的“子断点”。但是禁用正是您所需要的。如果您愿意,您还可以提供一系列实例,例如:
gdb> disable 5.1-2