欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-17 22:45:00
...


只讨论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

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