【Linux】调试器 gdb 及 ‘/r‘ 的使用

服务器 0

目录

前言

gdb

断点

打断点

查看、删除断点

断点使能

调试

显示数据

其他指令

‘/r’的使用

行缓冲区

小程序


前言

🥑在 Linux 下我们可以通过 gcc 进行编译,但与 vs 相比若想对代码进行调试,我们还需要学会使用调试器 gdb 

🥑我们都知道程序的发布方式有两种,release 版本和 debug 版本,而 release 版本是无法进行调试的,在 VS 之中默认为 debug 版本,并且可以通过选取来直接更改程序的不同版本。

🥑但在 Linux gcc/g++ 出来的二进制程序,默认是 release 模式,因此无法调试。若想转换成 debug 版本,则必须在源代码生成二进制程序的时候, 加上 -g 选项。

gcc -g -o text text.c

🥑同时我们也注意到,debug 版本的可执行程序明显占的空间较大,这是因为 release 版本是最终用户在使用的版本,且用户根本不需要对文件进行调试,为了节约空间占比,release 版本便不会加上文件的调试信息,这也是为什么 release 版本下无法进行调试的原因。

-rwxrwxr-x 1 Alpaca Alpaca 9544 Feb  3 11:56 text.debug-rwxrwxr-x 1 Alpaca Alpaca 8384 Feb  3 11:57 text.release

gdb

🥑当我们拿到 debug 版本的可执行文件之后就可以进行调试了。直接 gdb + 可执行文件名 就可以打开调试器了。

[Alpaca@VM-12-9-centos myfile]$ gdb text.debug    //gdb + 文件名GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7Copyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/Alpaca/myfile/text.debug...done.(gdb)                //进入后的命令行

🥑l + 行号(中间要有空格): 从该行开始向下打印10行。若代码过长再按回车会自动重复上一个指令进行操作。

(gdb) l 11	#include<stdio.h>2	#include<unistd.h>3	4	void plus(int* p)5	{6		*p *= 2;7	}8	9	int main()10	{(gdb)       //再按一次回车11		int count = 0;12		while (1)13		{14			printf("%d/n", count);15			count++;16			plus(&count);17		}18		return 0;19	}(gdb) 

🥑r :开始调试 ,与VS中的F5效果相同,若程序非死循环或过程中无断点则会直接执行到程序结束。

断点

打断点

🥑 d + 行号 :在该行打断点。

🥑 d + 函数名 : 在该函数有效行处打上断点。

(gdb) b 11            //以行号打断点Breakpoint 3 at 0x40054e: file text.c, line 11.(gdb) b main          //找函数打断点Breakpoint 1 at 0x40054e: file text.c, line 11.

查看、删除断点

🥑 info b :查看所有断点信息。

🥑 d + 断点编号 :删除断点

(gdb) info bNum     Type           Disp Enb Address            What3       breakpoint     keep y   0x000000000040054e in main at text.c:114       breakpoint     keep y   0x0000000000400555 in main at text.c:145       breakpoint     keep y   0x0000000000400569 in main at text.c:15
(gdb) d 4(gdb) info bNum     Type           Disp Enb Address            What3       breakpoint     keep y   0x000000000040054e in main at text.c:115       breakpoint     keep y   0x0000000000400569 in main at text.c:15

断点使能

🥑 disable :  禁用断点。(当禁用断点后再次运行直到程序结束才会停止)

🥑 enable :  使用断点。

调试

🥑 n :逐过程调试。(类似于VS中的F10,若遇到函数调用不会进入到函数之中)

🥑 :逐语句调试。(类似于VS中的F11,会进入到函数之中继续调试)

//逐语句Breakpoint 3, main () at text.c:1111		int count = 0;(gdb) n14			printf("%d/n", count);(gdb) n0Breakpoint 5, main () at text.c:1515			count++;(gdb) n16			plus(&count);(gdb) 17		}//逐语句Breakpoint 5, main () at text.c:1515			count++;(gdb) 16			plus(&count);(gdb) plus (p=0x7fffffffe42c) at text.c:66		*p *= 2;(gdb) 7	}(gdb) main () at text.c:1717		}

显示数据

🥑 p + 变量名 :打印出该变量当前的值。

🥑 display + 变量名:跟踪查看一个变量,每次停下来都显示它的值。

🥑 undisplay + 编号 : 取消对变量的跟踪查看。

(gdb) p count$4 = 2(gdb) display count3: count = 2(gdb) undisplay 3

其他指令

🥑 c :从一个断点处直接执行到下一个断点。

🥑 set var:修改变量的值。

🥑 finish : 执行完一个函数。

🥑 until + 行号:跳至该行。
🥑 bt :查看各级函数调用及参数。
🥑 quit :退出gdb。

‘/r’的使用

🥑在Linux下以下的三条语句会产生三种不一样的结果。

    printf("hello world/n");     //正常打印后暂停一秒                                                                                                                sleep(1);    printf("hello world");       //暂停了一秒后语句和提示符一起打印出来                                                                                                           sleep(1);    printf("hello world/r");     //无语句打印                                                                                                           sleep(1);
hello world[Alpaca@VM-12-9-centos myfile]$ hello world[Alpaca@VM-12-9-centos myfile]$[Alpaca@VM-12-9-centos myfile]$ 

行缓冲区

🥑在字符串被打印出来之前,会将其先加载到行缓冲区之中,但不是立刻就会打印出来。因此在第二条语句时,语句还没有打印出来系统就暂停了一秒钟,之后行缓冲区刷新,将之前的内容都打印出来, 因此第二个语句才会是先暂停一秒再打印。又因为提示符是跟随光标打印的,所以便跟在语句之后打印。

🥑我们都知道 /n 为换行符,而 /r 又被称为回车,会将光标会到本行的最开始。当我们使用 /n 便会强行刷新行缓冲区,使之前的数据被打印出来。而第三个语句之所以没有打印出语句则是因为 /r 使得光标回到本行开头,提示符从头开始打印将原来要打印出来的语句覆盖掉了,所以没有语句显示出来。

🥑若使用fflush对缓冲区进行刷新的话,便能够看到语句打印出来一秒钟后,就被系统的提示符覆盖打印了。

#include <stdio.h>#include <unistd.h>int main(){   printf("hello world/r");   fflush(stdout);                                                                                                                          sleep(1);   return 0;}

小程序

🥑通过上面第三个语句的启发,我们可以写出一个类似于进度条的小程序,通过每次重复覆盖打印,得到进度条在持续增长的效果。

#include<stdio.h>#include<string.h>#include<unistd.h> #define SIZE 101int main(){  int i = 0;  char s[SIZE];        //转换成重复打印一个数组  memset(s,0,SIZE*sizeof(char)); //对数组初始化  const char *lable ="|/-//";  while(i<=100)  {    if(i!=100)    {       s[i] = '>';     //i指向最高一位,作为箭头    }     printf("[%-100s][%3d%%][%c]/r",s,i,lable[i%4]); //把数组对其打印出来,并附上其他观赏性信息     fflush(stdout);                 //每次刷新缓冲区                                                                                                          s[i++] = '=';                   //进度条延长     usleep(100000);  }   printf("/n");   return 0; }

🥑好了这次调试器 gdb'/r' 的介绍就到这里结束了,关注博主共同进步!!

也许您对下面的内容还感兴趣: