聊聊关于C/C++调试的看法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Davincdada/article/details/85634684


只讨论 Linux 环境下的 C/C++ debug

在 Windows 环境下开发由很多优秀的 IDE 可以使用,而在 Linux 下开发C/C++,最好的开发环境并不是 IDE,而是一系列工具的组合。不要执着于争论到底是 ide 齐全还是 vim/emacs 效率高,只要用惯、用熟了,效率不会区别太大。确实存在某些场合只能使用 vim ,但这样并不能说明哪种更好。嗯……习惯、喜欢。

当然,vim 等一开始需要花点时间折腾,需要耐心和兴趣,不过维护好自己的vimrc等配置文件,之后在使用上如何就见仁见智了。

步骤 工具
编辑 vim/emacs/vscode + plugins
调试 gdb / log /valgrind / cppcheck / file / nm / ldd 等
编译 gcc / g++/ cmake / makefile / clang 等
链接 link
远程调试 gdb-server / ssh?
脚本 shell
分屏 tmux

debug 是什么

调试,是一种发现源代码错误,排查 Bug 的过程,错误的类型有语法错误,逻辑错误,内存泄露等。

debug 的步骤

  1. 插入打印语句------如printf、cout等打印语句,能够显示程序的动态过程,容易检查源程序的有关信息;缺点是大量无关数据,发现 bug 有偶然性。
  2. 运行部分程序------为了测试某段一段可能出错的代码,执行整个程序的做法是低效率的;因此应设法让程序只执行需要检查的程序段,提高效率。
  3. 借助调试工具------上面的方法可以说是“人肉debug“,只能在代码量少的情况下发挥作用。大多数语言有专门的调试工具,借助工具调试才是正确的 debug 打开方式。

debug 分类

  1. 静态调试------插入打印语句printf、cout,输出寄存器、关键变量的动态值。(低效)

  2. 动态调试------即使用调试工具分析程序的动态行为。如利用valgrind检查内存泄露问题;设置断点(程序语言自身提供,不是外部工具),分析程序此时的状态;使用内置的

    • 使用调试标记

      在源代码中使用相应的辅助代码,debug 完成之后 隐藏 这些代码的一种调试策略。借助 #define/#ifdef/#endif 三个编译指令。相当于使用 #define 定义宏,#ifdef / #endif 之间包含调试代码。调试完成后,生成发行版时,在编译器命令行参数中设置不提供调试标记,这段代码就会销毁。常用调试标记_DEBUG(VC++)

      #ifdef _DEBUG
      	std::cout << "something..." << std::endl;
      #endif
    • 使用调试变量

      运行时设置一个bool 类型的变量,决定特定调试程序段的开关,且该变量可以通过命令行参数设定。

      #include ...
      bool _debug_;
      int main(int argc, char* argv[])
      {
          if(_debug_){
              //do something
          }
      }
    • 使用内置宏

      __FILE__ / __FUNCTION__ / __LINE__ 自动获取有关模块、函数、宏的信息。

      {
      	std::cout << __FILE__ << std::endl;
      	std::cout << __FUNTION__ << std::endl;
      	std::cout << __LINE__ << std::endl;
      }

debug 调试跟踪工具

  • gdb ==> 最重要最常用最基础(Linux)

    • 设置断点,且断点可以是条件表达式
    • 快速定位 bug,如使用 bt / where 可以快速找到程序出现 core dump (核心转储)的位置。core dump就是程序运行中发生execption,异常退出时,由操作系统把程序当前的内存状况存储在一个core文件中,又叫做segmentation fault。
  • valgrind ==> 内存

    • 内存调试、内存泄漏检测以及性能分析
  • strace

    • 跟踪并显示用户程序中的系统调用的详细信息(parameters/return values/system call/time/…)
    • 适用于a.out/.exe或运行中的进程,用户可观察程序的运行状态
  • pstack

    查看进程的实时堆栈信息。

静态分析工具

  • cppcheck

    • C/C++代码缺陷静态检查,检测未使用的变量,越界访问,内存泄漏等问题。
    • 不同于其他编译器和分析工具,cppcheck只检查编译器检查不出来的bug,不检查语法错误。作为编译器的一种补充检查。
  • ldd

    ldd 命令可以查看当前 a.out/.exe或者动态库需要依赖那些动态库,以及缺少哪些动态库。ldd -r 可以报告缺少的目标对象和函数。

  • file

    查看文件类型,对于可执行文件或动态库,可查看使用需要 link 动态库,同时可查看是否包含符号表。file filename

  • nm

    列出目标文件中的符号。通常情况下,对于链接问题可以通过该命令的-D -u参数来查看相关符号。nm -CDu filename

  • strip

    清理共享库或可执行文件中的符号信息和调试信息,通常在程序发布前使用。

性能调试工具

  • perf ==> CPU

    分析应用程序或内核代码性能。对单个程序做函数调用次数、上下文切换次数、中断次数等信息进行统计。

  • prof/gprof

    显示程序运行所用的 时间 具体用在什么操作上,可用于性能优化。

猜你喜欢

转载自blog.csdn.net/Davincdada/article/details/85634684