19 Star 204 Fork 309

飞行器智能感知与控制/learn_programming

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

[TOC]

Debug技巧

如何快速发现程序当中的问题,并找到解决办法,是一项非常重要编程技能。下面列了一些常用的方法,大家可以先了解,在遇到问题的时候,琢磨哪种方法比较适合,以及如何灵活应用并组合多种方法去解决所面临的问题。

0. 流程分析/大脑运行代码

其实最快的Debug方式是用自己的大脑运行程序,然后分析各个变量的变化、时序、函数调用关系等等。可能刚开始对程序进行流程分析太难,因为还没有建立起程序分析的能力,因此建议各位强迫自己先从程序阅读分析开始着手。

0.1 程序分析的基本思路

  • 程序本质上是一个倒长的树,功能、函数大多数情况下可以细分成更小的函数、模块等。通过层层深入分析的方式能够更好掌握程序的整体的架构,根据程序中模块、类、函数等关系,层层深入进去去看、去分析。

    • 先把main里面的调用看完,这时候先不要急着深入进去看不清楚的函数或者类
    • main函数都看完之后,然后再逐个模块、类、函数深入进去分析
    • 也就是说采用广度优先的遍历方式去看、去分析代码。
  • 类似的,在看当前函数、或者类的时候,先集中精力在所关注的函数、类

    • 它所调用的其他函数、类,需要先假设调用的那些函数、类是符合预期设计。
    • 当看完当前的函数、类之后,在对所调用的函数、类直接的调用关系、参数传递、返回值等进行分析。

0.2 打印工具

可以借助Log/打印工具帮助分析程序

1. backtrace

对于C、C++程序,内存访问异常是最常见的一类问题。遇到程序内存访问异常导致的崩溃,不用害怕,目前编程语言、操作系统、IDE都有很好的支持,能够很快的定位到出现的问题地方。

针对示例程序 backtrace ,具体的操作包括:

  • 编译的时候打开Debug模式,否则编译器不会把源代码、符号编译到程序中,无法直接看到错误地点的代码。针对qmake具体的操作是: qmake backtrace.pro CONFIG+=debug

  • 编译程序,输出的程序在./build/backtrace

  • 运行gdb ./build/backtrace, 然后输入run指令执行程序,出错之后输入 bt后者backtrace指令,能够将调用的堆栈打印出来,可以看到

backtrace

通过调用堆栈所提供的信息,能够看到最后出错的地方在程序test_backtrace.cpp的第10行,从下图可以看出有一个非法的指针赋值。

backtrace

2. 单步跟踪

我们在编程的时候,有些非语法问题可能很难找到定位,这时候我们就需要进行程序的调试工作了。一般我们都会在程序加断点,然后再利用单步调试查看变量的值是否异常。

1 - 我们打开 QtCreator 界面程序的主窗口

我们将编辑的窗口切换到Debug的窗口

点击那个甲虫的标志

img

2 - 下面绿色的播放按钮是编译运行,带甲虫标志的是调试编译运行

在右上角我们可以看到变量值的信息

3 - 不过这时我们发现调试程序也是很快就运行完了

那个变量窗口也是什么信息都没有

那是因为我们没加断点,程序很快就运行结束了

img

4 - 我们在程序的适当位置添加断点

然后再点击编译运行

发现程序黄色的进度条停止在断点那里

而变量窗口也有我们需要的信息了

我们可以单击下面的单步运行查看变量值的变化是否正确

img

5 - 我们在变量窗口点击Add 可以添加那里原本没有的变量

img

6 - 比如我们这里只显示了结构体指针p的值,而没有显示p[1]的值

我们可以输入p[1],就行了

img

7 - 可以看到,在变量窗口已经显示出了p[1]的值了

img

3. log文件分析

4. 单元测试

gtest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C++单元测试框架,由google公司发布。gtest是为在不同平台上为编写C++测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。

TEST(test_case_name, test_name)
TEST_F(test_fixture,test_name) //多个测试场景需要相同数据配置的情况,用TEST_F。TEST_F test fixture,测试夹具,测试套,承担了一个注册的功能。

TEST(test_case_name, test_name)

TEST_F(test_fixture,test_name) //多个测试场景需要相同数据配置的情况,用 TEST_F 。TEST_F test fixture,测试夹具,测试套,承担了一个注册的功能。

TEST宏的作用是创建一个简单测试,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言来进行检查。后续文章还会提到TEST_P这个宏,在这里就先不介绍了。

可以参考示例程序,或者更详细的说明

5.Debug工具

Valgrind是主要用于检测内存问题的Debug工具,默认使用memcheck,可以检测内存未初始化读取越界动态内存管理错误等问题。linux下使用apt-get即可安装,非常方便。这里是入门介绍官网

debug 实例

stack smash detected:此为GCC的内存保护机制,一般是内存溢出导致的错误,可以在gdb中使用where命令查询并解决。

多线程中循环的顺序导致的问题:在未经处理时,多线程的循环顺序是不可控制的,此时会导致跨线程的数据调用出现越界的问题(数组等尤为有可能),需要人为规范其线程顺序。

double free detected in tcache2:重复删除错误,多由于stl容器的push_back运作机制导致,该方法会生成对应对象的临时副本,导致产生两个指针指向同一个对象的情况,此时如果调用delete(可能并非显示调用,而是C++自动调用)方法则会导致其析构函数删除同一对象两次,导致错误。deemo代码如下:

std::vector<T> arr_t;	//一个T类的数组
T t;	//生成T类的对象
arr_t.push_back(t);	//将此对象存入数组,此时产生了t的临时副本,并会导致在delete时产生错误

解决办法:1.使用T类的指针创建T类的指针数组而非对象数组,即std::vector<T*> arr_t;,此时arr_t中存储的为指针,对象仅有一个,不会导致重复删除。(已验证)

2.保证复制时的对象是独立的(即杜绝两个指针指向同一对象的情况)。可以使用pusk_back以外的复制方法,或者智能指针。参考这里(听起来可行)

3.在类内部阻止拷贝构造函数的非期望调用(即阻止产生临时对象,即可阻止产生额外的指针)。参考这里(或许有用,有待验证)

编译错误

undefined reference to 'pthread_create':C++库文件缺失,需要手动添加提示的库,例如 -lpthread

6.Clion

  • Clion 是一款专门开发 C 以及 C++ 所设计的跨平台的 IDE。它是以 IntelliJ 为基础设计的,包含了许多智能功能来提高开发人员的生产力。
  • 这种强大的 IDE 帮助开发人员在 Linux、OSX 和 Windows 上来开发 C/C++ ,同时它还能使用智能编辑器来提高代码质量、自动代码重构并且深度整合 Cmake 编译系统,从而提高开发人员的工作效率。
  • CLion 支持 GCC、clang、MinGW、Cygwin 编译器以及 GDB 调试器。提供对 Cmake 支持:包含自动处理 Cmake changes 和 Cmake Targets,更新新创建的 C/C++ 档案以及 Cmake Cache 编辑器。

6.1 Clion的安装(Linux)

  • 官网下载链接
  • 解压缩包,运行目录bin下的cling.sh安装
  • 在License Activation页面,需要在Activation code中输入激活码才可以使用Clion
  • 激活码
    • 学生认证可以使用一年
    • 淘宝8.9元购买,可永久使用
  • 如果出现安装错误,那就是cmake库没安装,终端执行命令
sudo apt-get install cmake

6.2 Clion的启动

如果不经过任何处理,每次启动clion必须运行目录bin下的cling.sh,对此有以下两种解决方法

  • 1.在.bashrc中加入以下命令
alias clion="/home/xhjack/clion-2022.3.3/bin/clion.sh"##不要盲目复制,使用自己clion.sh所在的绝对路径

这样在终端中输入 clion 即可启动

  • 2.在桌面创建快捷方式,可自行参考链接

6.3 Clion的debug(ROS)

Clion支持调试ROS功能包的代码 example:/home/xhjack/catkin_ws/src/basic/takeoff_land.cpp

  • 在file-open打开/home/xhjack/catkin_ws/src/basic功能包,配置默认即可,点击OKimg
  • 打开gazebo仿真环境
roslaunch px4 mavros_posix_sitl.launch
  • 打开takeoff_land.cpp
  • 点击Clion中右上角绿色三角符号即可运行img
  • 打上断点,点击Clion中右上角绿色爬虫符号即可开始调试,程序会停止在断点处,可查看变量img

7. 参考资料

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/pi-lab/learn_programming.git
git@gitee.com:pi-lab/learn_programming.git
pi-lab
learn_programming
learn_programming
master

搜索帮助