在gdb中打印C ++ std ::字符串集的第一个元素?

时间:2015-11-16 18:10:19

标签: c++ gdb

正如Element at index in a std::set?所解释的那样,没有"直接"在std::set中按索引进行随机访问 - 所以,我在这里尝试使用它返回迭代器的.begin()方法...这是一个简单的最小例子:

// g++ --std=c++11 -g test.cpp -o test.exe

#include <iostream>
#include <set>

int main()
{
  std::set<std::string> my_set;
  my_set.insert("AA");
  my_set.insert("BB");
  std::cout << "Hello World!" << std::endl;
  return 0;
}

我最终想要做的是在我的实际问题中使用gdb dprintf类型中断 - 我不想更改代码,因此不添加额外的迭代器变量。由于dprintf使用格式说明符,其中%s用于C样式字符串,因此我最终不需要引用my_set的第一个元素,但我还需要在其上调用.c_str() - 所有这些都在一行中。 (在我的实际问题中,我有一个自定义String类的std::set,它有一个自定义方法来获取C风格的字符串。)

问题是,我找不到正确的语法来访问第一个元素:

$ gdb --args ./test.exe
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ./test.exe...done.
(gdb) b test.cpp:11
Breakpoint 1 at 0x8048bf8: file test.cpp, line 11.
(gdb) r
Starting program: /tmp/test.exe 

Breakpoint 1, main () at test.cpp:11
11    std::cout << "Hello World!" << std::endl;
(gdb) p my_set
$1 = std::set with 2 elements = {[0] = "AA", [1] = "BB"}
(gdb) p my_set.begin()
Cannot evaluate function -- may be inlined
(gdb) p my_set->begin()
Cannot resolve method std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::begin to any overloaded instance
(gdb) printf "%s", my_set.begin()
Cannot evaluate function -- may be inlined

是否可以使用std::set&#39; s gdb在这样的上下文中打印printf的第一个值,而无需更改代码(例如,添加迭代器变量)?

1 个答案:

答案 0 :(得分:0)

嗯,我得到了某个地方,感谢@AndreyStarodubtsev和@Amadeus的评论。

正如@Amadeus所指出的那样 - 事实证明,确实你必须对程序中的类型有某种引用,否则它可能会被优化掉。因此,调试时的OP示例将给出:

(gdb) p ((std::string*)(my_set._M_t._M_impl._M_header._M_left+1))->c_str()
A syntax error in expression, near `)(my_set._M_t._M_impl._M_header._M_left+1))->c_str()'.
(gdb) p std::string
No symbol "string" in namespace "std".

...但是,只是一个变量引用似乎足以解决这个问题:

// g++ --std=c++11 -g test.cpp -o test.exe

#include <iostream>
#include <set>

std::string aa; // just to have reference to std::string

int main()
{
  std::set<std::string> my_set;
  my_set.insert("AA");
  my_set.insert("BB");
  std::cout << "Hello World!" << std::endl;
  return 0;
}

...虽然这是代码更改,但我不必添加新的实际代码行来引用迭代器。然后,gdb会话如下所示:

$ gdb --args ./test.exe
...
Reading symbols from ./test.exe...done.
(gdb) b 13
Breakpoint 1 at 0x8048c38: file test.cpp, line 13.
(gdb) r
Starting program: /tmp/test.exe 

Breakpoint 1, main () at test.cpp:13
13    std::cout << "Hello World!" << std::endl;
(gdb) p ((std::string*)(my_set._M_t._M_impl._M_header._M_left+1))->c_str()
$1 = 0x804d014 "AA"
(gdb) printf "'%s'\n", ((std::string*)(my_set._M_t._M_impl._M_header._M_left+1))->c_str()
'AA'

访问my_set的第一个节点(显然是节点的“红黑树”)的语法,我查阅了@AndreyStarodubtsev提到的https://gist.github.com/skyscribe/3978082 gdb脚本,特别是函数pset(由于某种原因往往会给我语法错误 - 可能是因为对std::string的优化引用)