GDB调试器

前言:

GDB(GNU Debugger)是一个用来调试C/C++程序的功能强大的调试器,是Linux系统开发 C/C++最常用的调试器
程序员可以使用GDB来跟踪程序中的错误,从而减少程序员的工作量。
Linux 开发C/C++ 一定要熟悉 GDB
VSCode是通过调用GDB调试器来实现C/C++的调试工作的;
Windows 系统中,常见的集成开发环境(IDE),如 VS、VC等,它们内部已经嵌套了相应的调试
GDB主要功能:
设置断点(断点可以是条件表达式)
使程序在指定的代码行上暂停执行,便于观察
单步执行程序,便于调试
查看程序中变量值的变化
动态改变程序的执行环境
分析崩溃程序产生的core文件
4.1 常用调试命令参数
调试开始:执行gdb [exefilename] ,进入gdb调试程序,其中exefilename为要调试的可执行文件名

$(gdb)help(h)

$(gdb)run(r))

$(gdb)start

$(gdb)list(l))

$(gdb)set

$(gdb)next(n)

$(gdb)step(s)	# 查看命令帮助,具体命令查询在gdb中输入help + 命令

# 重新开始运行文件( run-text:加载文本文件, run-bin:加载二进制文


# 单步执行,运行程序,停在第一行执行语句

# 查看原代码(list-n,从第n行开始查看代码。 list+ 函数名:查看具体函


# 设置变量的值

# 单步调试(逐过程,函数直接执行)

# 单步调试(逐语句:跳入自定义函数内部执行)

$(gdb)backtrace(bt) # 查看函数的调用的栈帧和层级关系

$(gdb)frame(f)  # 切换函数的栈帧

$(gdb)info(i)   # 查看函数内部局部变量的数值

$(gdb)finish    # 结束当前函数,返回到函数调用点

$(gdb)continue(c)   # 继续运行

$(gdb)print(p)  # 打印值及地址

$(gdb)quit(q)   # 退出gdb
	$(gdb)break+num(b)

$(gdb)info breakpoints

$(gdb)delete breakpoints

$(gdb)display

$(gdb)undisplay

$(gdb)watch

$(gdb)i watch

$(gdb)enable breakpoints

$(gdb)disable breakpoints

$(gdb)x

$(gdb)run argv[1] argv[2]	# 在第num行设置断点

# 查看当前设置的所有断点

num(d) # 删除第num个断点

# 追踪查看具体变量值

# 取消追踪观察变量

# 被设置观察点的变量发生修改时,打印显示

# 显示观察点

# 启用断点

# 禁用断点

# 查看内存x/20xw 显示20个单元, 16进制, 4字节每单元

# 调试时命令行传参
	$(gdb)set follow-fork-mode child#Makefile项目管理:选择跟踪父子进程(fork())

Tips:

  1. 编译程序时需要加上-g,之后才能用gdb进行调试: gcc -g main.c -o main
  2. 回车键:重复上一命令
    4.2 【实战】命令行调试
    给出一段简单代码,准备调试。
#include 
using namespace std;

int main(int argc,char **argv)
{
int N = 100;
int sum = 0;
int i = 1;

// calculate sum from 1 to 100
while (i <= N)
{
sum = sum + i;
i = i + 1;
}

cout << "sum = " << sum << endl;
cout << "The program is over."   << endl;

return 0;
}

gdb调试过程
GDB调试器_第1张图片
GDB调试器_第2张图片

GDB调试器_第3张图片
b main
在main函数起始处设置断点

vim 显示行号 :set nu
GDB调试器_第4张图片

用gdb调试程序的bug
greet.c

#include
int display1(char *string);
int display2(char *string);

int main()
{
	char string[] = "Embedded Linux";
	display1 (string);
	display2 (string);
}
int display1 (char *string)
{
	printf ("The original string is %s \n",string);//%s表示字符串的占位符,display1直接输出string
}
int display2 (char *string1)//变量不重名
{
	char *string2;/*一个字符型的指针(指针就是内存地址)。所有实际数据类型,不管是整型、浮点型、字符型,
	还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。

    不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。*/
	int size,i;
	size = strlen (string1);/*strlen是一个函数,sizeof是一个单目运算符。

strlen 它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符)。
关键字 sizeof 是一个单目运算符,参数可以是数组、指针、类型、对象、函数等
strlen使用时注意事项:

strlen只能用char*做参数,且必须是以''\0''结尾的。换句话说:strlen只能计算字符串的长度。

sizeof使用时注意事项:

1 对于直接的调用sizeof,如果是数组首地址,sizeof会输出数组所占地址空间的大小(字节为单位)。
如果是一个指针的话,则输出在该系统中地址的字节宽度,即(位宽/8)。*/
	string2 = (char *) malloc (size + 1);/*如果要存储整个学校的人数时,会出现内存不够用的情况;
	当我们开辟全校人数大小的数组时,输入一个班人数的大小时,会出现内存浪费的情况。
为了应对上述问题,我们引入malloc函数。
malloc是动态内存分配函数,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址
malloc函数原型
extern void *malloc(unsigned int num_bytes);
意为分配长度为num_bytes字节的内存块
头文件#include
malloc函数返回值
如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

malloc函数使用注意事项
malloc函数的返回的是无类型指针,在使用时一定要强制转换为所需要的类型。
**(敲黑板)重点:在使用malloc开辟空间时,使用完成一定要释放空间,如果不释放会造内存泄漏。
在使用malloc函数开辟的空间中,不要进行指针的移动,
因为一旦移动之后可能出现申请的空间和释放空间大小的不匹配
使用形式
malloc只开辟空间,不进行类型检查,只是在使用的时候进行类型的强转。
mallo函数返回的实际是一个无类型指针,必须在其前面加上指针类型强制转换才可以使用
在使用malloc函数之前我们一定要计算字节数,malloc开辟的是用户所需求的字节数大小的空间。
如果多次申请空间那么系统是如何做到空间的不重复使用呢?
在使用malloc开辟一段空间之后,系统会在这段空间之前做一个标记(0或1),
当malloc函数开辟空间如果遇到标记为0就在此开辟,如果为1说明此空间正在被使用。
free函数
作用:释放malloc(或calloc、realloc)函数给指针变量分配的内存空间。
注意:使用后该指针变量一定要重新指向NULL,防止悬空指针(失效指针)出现,有效规避错误操作。
free函数在释放空间之后,把内存前的标志变为0,且为了防止数据泄露,它会把所释放的空间用cd进行填充。
*/
	for (i = 0; i < size; i++)
	{
		string2[size - i] = string1[i];/*在for循环的作用下,string1的头依次复制给string2的尾
		string1的第一个给string2的最后一个,以此*/
	}
	string2[size+1] = ' ';//在string2的尾加个空字符
	printf("The string afterward is %s\n",string2);
}

先在vim里用:set nu显示行号
GDB调试器_第5张图片

再在 for 和print处打断点

b 62
b 68

GDB调试器_第6张图片
发现string2[0]没有赋值
修改string2[size - i] = string1[i]string2[size - i - 1] = string1[i]

能翻转字符串
在这里插入图片描述

你可能感兴趣的:(Linux篇,linux,bash,运维)