zoukankan      html  css  js  c++  java
  • [干货] gdb使用指南

    忽然发现自己欠缺点调试能力,所以就学习了一下,来写了篇gdb使用指南,以作备用。

    Before we start

    1.gdb是啥?
    是一个UNIX及UNIX-like下的调试工具。使用gdb,需要在cmd命令窗口下操作。

    2.为啥要用gdb?
    有的时候静态查错,输出中间变量调试信息,devcpp自带的debug都不好使,就得用gdb。

    3.gdb好在哪?
    据zhx julao说,熟练使用gdb可以在5min内准确找出代码错误。

    1.准备工作

    首先我们需要配置好系统的环境变量。如果电脑是在Linux环境下,那么第1部分所有工作都已经做好了,可直接跳过。此部分只针对windows系统,且Win7Win10相同。

    我们的编译器,大多都是使用devcpp自带的MinGW32/MinGW64。现在我们要找到它。

    打开C盘,进入Programs(x86),找到Dev-Cpp文件夹,可以发现里面有一个MinGW32/MinGW64(这个是根据电脑是32位还是64位而定)文件夹,点进去找到bin。

    打开bin(垃圾桶)文件夹,我们惊奇地发现所有编译器都安安静静地待在里面(gdb也在呢!)。然后,我们需要复制现在所处的这个位置的地址。

    退回到桌面,找到“我的电脑”或者“计算机”,右键进入计算机属性界面,找到“高级系统设置”。

    然后在高级系统设置里找到环境变量,新建用户变量。

    变量名:大写PATH,变量值:刚才复制下来的bin文件夹地址。

    一路确定出去就配好了,不要点取消。

    2.检查程序是否CE

    我写了一段把0~100之间的整数二进制输出的代码,叫1.cpp。接下来我们就调试它。

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int a[100];
    void print(int x)
    {
    	if(!x)
    	{
    		printf("0
    ");
    		return;
    	}
    	int i,j=0;
    	while(x)
    	{
    		a[++j]=x&1;
    		x>>=1;
    	}
    	for(i=j;i>=1;i--)
    	printf("%d",a[i]);
    	printf("
    ");
    	return;
    }
    int main()
    {
    	int i;
    	for(i=0;i<=100;i++)
    	print(i);
    	return 0;
    }
    

    检查是否CE,我们不要用devcpp,因为有一些库devcpp会自动补全,会造成问题。

    我们用cmd指令来编译。

    打开1.cpp(我们要调试的代码)的目录,地址栏输入cmd,回车。

    我们接下来所有工作都是在这个命令窗口里操作。

    输入编译命令g++ 1.cpp -o 1.exe,意思是把1.cpp用g++编译成1.exe。

    如果回车之后什么事也没有,那么恭喜,编译成功。

    如果提示找不到g++,那么环境变量配错了,再回去配一次。

    如果弹出编译信息error,那么是CE了。warning则没有CE。

    上图是CE的状况。

    如果考试题目pdf的第一页里有编译选项,那就在刚才的指令的后面加上编译选项的全文,比如——

    检查完代码,没有CE,我们终于可以开始调试了。

    3.简单的调试指令

    首先要进入调试工具gdb。我们要重新编译代码,在编译选项的后面加上指令-g。比如,g++ 1.cpp -o 1.exe -O2 -g。编译完成之后,键入指令gdb 1.exe

    P.S.上图中只需要打一遍g++ 1.cpp -o 1.exe -O2 -g即可,不用编译两次qwq~

    然后会出来这么一大堆东西。

    我们不管别的,只看倒数第二行红线画出来的东西。如果显示reading...done,那么表示我们的代码被gdb读取成功了,可以开始调试了。

    下面我们开始调试吧。

    1)运行整段代码:r

    敲进去指令r,我们看到gdb把整段代码运行了一遍,还把输出给了我们。如果不想看到这些输出,可以用文件。

    2)在某行设断点:b 1(在第一行设断点,其他以此类推)

    有的时候我们需要让程序在某一行停下来,这个停下来的位置就叫断点。在第1行设断点,指令叫做b 1

    设好所有断点,然后再敲r开始运行。

    假如我们在第25行设断点,那么程序会执行完第25行,停在第26行,如下图。

    3)在某个函数设断点:b print(在print()函数设断点,其他以此类推)

    设好函数断点之后,会在刚刚进入函数的时候停下来,如下图。

    4)条件断点:b 27 if (i==10)(在i==10时在第27行停下来,其他以此类推)

    if里面的东西,语法和c++一样。

    效果基本和行断点一样qwq。

    但是这次是还没有执行第10遍循环就停了下来。

    5)一步一步执行:s

    比如我们就从刚才停下来的位置开始一步一步执行:

    可以看到,每一次都只执行了一句话,而且所有的地方都会被展示出来——例如进出函数,if语句执行与否,等等。

    但是这样做会出现问题,比如如果我们继续执行下去——

    再按十几次s之后,就出现上图一大堆看不懂的东西了。

    什么情况?

    其实是程序进到了printf()函数的里面,所以让人看不懂了的。

    那怎么避免这种情况嘞?

    6)一步执行完当前函数:finish

    finish,就直接退回到我们的代码里了。

    如果本来就不想进到函数里面呢?

    7)执行下一步,如果是函数一步执行完:n

    直接敲n,可以看到程序没有进入printf函数,如下图——

    8)继续不断执行,直到下一个断点:c

    我们先设上下一个断点,然后敲c

    可以看到程序执行完86停下,87还没执行。

    9)打印某个变量的值:p i(打印i的值,其余以此类推)

    很简单。注意,如果是递归的话,只显示当前层上的值

    10)持续跟踪某个变量的值:display i(持续跟踪i,其余以此类推)

    也很简单。敲完display i之后,执行sn等等都可以。

    11)退出gdb:q

    有时候gdb还会不舍地和你挽留一句qwq:

    4.测试时间和内存

    1)测试内存

    首先还是编译代码,要加上-g。然后,输入size 1.exe

    显示的第三个和第四个数(计算方式有微小的差异)就是以B为单位的运行内存。只要保证这两个数都不MLE,代码一定安全。

    2)测试时间

    首先还是编译代码,要加上-pg,注意了,是-pg,因为我们使用的工具变了,叫gprof

    编译完之后,直接输入1.exe,意思是在cmd里运行一遍1.exe。

    然后,我们整个程序所有函数的运行时间信息都被gprof记下来了。现在我们要导出这些数据,用的是指令gprof 1.exe > test.out,意思是把信息导出到test.out里。

    打开文件test.out。

    所有的运行时间信息都在里面了!

    注:如果函数里面只有一句话,c++会把它优化掉,所以这个函数执行时间为0。

    End

    gdb大法好!

    也许它现在看起来比较麻烦,但是我尽量还是坚持zhx学长的建议,常用gdb吧。

    祝:NOIP CSP rp++

    完结撒花!

    orz~

  • 相关阅读:
    type() & dir()

    手机操作API
    APP模拟手势高级操作
    APP元素事件操作API
    APP元素信息操作API
    APP元素定位操作
    手机控件查看工具uiautomatorviewer
    App基础操作API
    Appium入门
  • 原文地址:https://www.cnblogs.com/Rain142857/p/11830821.html
Copyright © 2011-2022 走看看