针对gdb出现DWARF错误的问题:在build文件夹中运行:添加环境变量
export CXXFLAGS="-g -gdwarf-4"
export CFLAGS="-g -gdwarf-4"
然后清空build文件夹,重新编译,就OK了。
debug时,出现下面的情况,如何查看数值:
(gdb) p coords0
$1 = (petibm::type::RealVec2D &) @0x5555565abf70: {<std::_Vector_base<std::vector<dou\
ble, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<doub\
le> > > >> = {_M_impl = {<std::allocator<std::vector<double, std::allocator<double> >\
>> = {<std::__new_allocator<std::vector<double, std::allocator<double> > >> = {<No d\
ata fields>}, <No data fields>}, <std::_Vector_base<std::vector<double, std::allocato\
r<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::_Vector\
_impl_data> = {_M_start = 0x5555565ac060, _M_finish = 0x5555565acbb8, _M_end_of_stora\
ge = 0x5555565acbb8}, <No data fields>}}, <No data fields>}
先启用GDB的打印自动排版
(gdb) set print pretty on
就会变成:
(gdb) p coords
$3 = (petibm::type::RealVec2D &) @0x5555565ac0e8: {
<std::_Vector_base<std::vector<double, std::allocator<double> >, std::allocator<std\
::vector<double, std::allocator<double> > > >> = {
_M_impl = {
<std::allocator<std::vector<double, std::allocator<double> > >> = {
<std::__new_allocator<std::vector<double, std::allocator<double> > >> = {<No \
data fields>}, <No data fields>},
<std::_Vector_base<std::vector<double, std::allocator<double> >, std::allocator\
<std::vector<double, std::allocator<double> > > >::_Vector_impl_data> = {
_M_start = 0x5555565ae270,
_M_finish = 0x5555565aedc8,
_M_end_of_storage = 0x5555565aedc8
}, <No data fields>}
}, <No data fields>}
如果不希望每次启动 GDB 都要手动输入,可以创建配置文件:
# 在家目录创建 .gdbinit 文件
echo "set print pretty on" >> ~/.gdbinit
echo "set print array on" >> ~/.gdbinit
echo "set print object on" >> ~/.gdbinit
举一个例子:
查看coords[0][0]的命令:
(gdb) p coords._M_impl._M_start[0]._M_impl._M_start[0]
$4 = 0.5990000065797233
再举一个例子:
查看body 的类型:
(gdb) p body
$2 = (petibm::type::SingleBody &) @0x5555565abe70: {
<std::__shared_ptr<petibm::body::SingleBodyBase, (__gnu_cxx::_Lock_policy)2>> = {
<std::__shared_ptr_access<petibm::body::SingleBodyBase, (__gnu_cxx::_Lock_policy)\
2, false, false>> = {<No data fields>},
members of std::__shared_ptr<petibm::body::SingleBodyBase, (__gnu_cxx::_Lock_poli\
cy)2>:
_M_ptr = 0x5555565abee0,
_M_refcount = {
_M_pi = 0x5555565abed0
}
}, <No data fields>}
查看body里面的成员变量nPts:
(gdb) p body._M_ptr->nPts
$3 = 121
为什么访问路径不同?
你可能会好奇:为什么访问 coords[0][0] 需要 coords._M_impl._M_start[0]._M_impl._M_start[0] 这么复杂的路径,而访问 body 的成员只需要 body._M_ptr->nPts?
1. coords 的类型结构
coords 的类型是 petibm::type::RealVec2D,从 GDB 输出可以看出它继承自:
std::_Vector_base<std::vector<double>, ...>→ 这是一个二维向量- 内部包含
_M_impl(实现对象) _M_impl包含_M_start(指向第一个元素的指针)
所以访问路径是:
coords → _M_impl → _M_start[0] → 第一个一维向量
第一个一维向量 → _M_impl → _M_start[0] → 第一个 double 值
2. body 的类型结构
body 的类型是 petibm::type::SingleBody,从 GDB 输出可以看出:
- 它继承自
std::__shared_ptr<petibm::body::SingleBodyBase> _M_ptr是共享指针的原始指针成员nPts是SingleBodyBase类的公有成员变量
所以访问路径是:
body → _M_ptr → nPts
3. 关键区别
| 特性 | coords (二维向量) | body (共享指针) |
|---|---|---|
| 类型 | std::vector<std::vector<double>> | std::shared_ptr<SingleBodyBase> |
| 访问方式 | 通过迭代器/指针访问元素 | 通过指针访问对象成员 |
| GDB 路径 | 需要深入到内部实现 | 只需要解引用指针 |
| C++ 代码等价 | coords[0][0] | body->nPts |
4. 为什么 GDB 需要这么长的路径?
因为 GDB 在调试时:
- 不能直接调用运算符重载:
coords[0][0]在 C++ 代码中是operator[]的调用,但 GDB 不能直接调用这个运算符 - 需要直接访问内存布局:GDB 必须按照实际的内存结构来访问数据
std::vector的实现细节:std::vector内部使用_M_start、_M_finish、_M_end_of_storage三个指针来管理内存
5. 简化访问的方法
如果你觉得路径太长,可以定义 GDB 便利函数:
# 定义查看二维向量元素的函数
(gdb) define pvec2d
>p $arg0._M_impl._M_start[$arg1]._M_impl._M_start[$arg2]
>end
# 使用
(gdb) pvec2d coords 0 0
$5 = 0.5990000065797233
或者使用类型转换(如果知道具体类型):
(gdb) p ((std::vector<std::vector<double>>*)&coords)->at(0).at(0)
总结
-
在于它们在内存中呈现的
空间拓扑结构完全不同! -
coords是二维std::vector,需要访问两次内部迭代器才能到达元素 -
body是shared_ptr,只需要一次解引用就能访问对象成员 -
GDB 不能直接调用
operator[],所以需要手动展开内存结构 -
这是 C++ STL 容器在调试时的常见情况,理解容器内部结构有助于高效调试
371

被折叠的 条评论
为什么被折叠?



