编译命令gcc -g -omain memlook.c然后运行gbd ./main进入调试。
(gdb) list 15
10 }
11 i = 0;
12 for (; i < 10; i++)
13 {
14 printf("%d ",p[i]);
15 }
16 free(p);
17 return 0;
18
19 }
在free(p)处设置断点break 16
(gdb) break 16
Breakpoint 1 at 0x74e: file memlook.c, line 16.
然后运行
(gdb) run
Starting program: /mnt/hgfs/linux/cpp/gdblearn/main
Breakpoint 1, main () at memlook.c:16
16 free(p);
接下来查看指针p指向的数据
方式一:
当需要查看一段连续内存空间的值的时间,可以使用GDB的“@”操作符,“@”的左边是第一个内存地址,“@”的右边则是想查看内存的长度。
int *array = (int *) malloc (len * sizeof (int));
在GDB调试过程中这样显示出这个动态数组的值:
p *array@len
(gdb) print *p@10
$1 = "\000\001\002\003\004\005\006\a\b\t"
(gdb) print *(char*)p@10
$2 = "\000\001\002\003\004\005\006\a\b\t"
(gdb) print *(int*)p@10
$3 = {50462976, 117835012, 2312, 0, 0, 0, 1041, 0, 540090416, 540221490}
(gdb)
我们可以使用examine命令(缩写为x)来查看内存地址中的值。examine命令的语法如下所示:
x/<n/f/u> <addr>
<addr>表示一个内存地址。“x/”后的n、f、u都是可选的参数,n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容;f 表示显示的格式,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i;u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4字节。u参数可以被一些字符代替:b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指定的内存地址开始,读写指定字节,并把其当作一个值取出来。n、f、u这3个参数可以一起使用,例如命令“x/3uh 0x54320”表示从内存地址0x54320开始以双字节为1个单位(h)、16进制方式(u)显示3个单位(3)的内存。
print的输出格式包括:
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
示例如下:
(gdb) x/10db p
0x555555756260: 0 1 2 3 4 5 6 7
0x555555756268: 8 9
(gdb) x/10dh p
0x555555756260: 256 770 1284 1798 2312 0 0 0
0x555555756270: 0 0
(gdb)
x/10db p 表示查看p指针指向的内存中往后10个地址的数据,并以十进制格式显示变量,以单字节读写指定字节。
(gdb) print *(int*)p
$5 = 50462976
*(int*)p表示将按照整型指针处理。
更多案例:
main()
{
char *c = "hello world";
printf("%s\n", c);
}
char *c = "hello world";
下一行设置断点后:
(gdb) l
1 main()
2 {
3 char *c = "hello world";
4 printf("%s\n", c);
5 }
(gdb) b 4
Breakpoint 1 at 0x100000f17: file main.c, line 4.
(gdb) r
Starting program: /Users/songbarry/main
Reading symbols for shared libraries +. done
Breakpoint 1, main () at main.c:4
4 printf("%s\n", c);
可以通过多种方式看C指向的字符串:
(gdb) p c
$1 = 0x100000f2e "hello world"
(gdb) x/s 0x100000f2e
0x100000f2e: "hello world"
(gdb) p (char *)0x100000f2e
$3 = 0x100000f2e "hello world"
将第一个字符改为大写:
(gdb) p *(char *)0x100000f2e='H'
$4 = 72 'H'
再看看C:
(gdb) p c
$5 = 0x100000f2e "Hello world"
run | r : 运行程序,当遇到断点的时候,程序会在断点处停止运行,等待用户输入下一步的命令。
start :运行,从第一条语句开始
continue | c:继续执行,直到下一个断点处(或运行结束)。
step | s :执行下一句,如果下一执行语句为函数,进入函数
next | n | 换行 :执行下一句,不进入函数
0x01:毕竟学Linux就要学会
gdb
调试C语言啦,这里我们来看看
指针
在内存里到底是长什么样子的,毕竟眼见为实,不多说来调试看看吧;
0x02:代码如下所示
#include <stdio.h>
int main()
char a = 'c';
char *p = &a;
char **ptr = &p;
return 0;
gcc -g -o test test.c --> 生成调试文件
之前有介绍过如何使用
gdb
来
查看
当前
指针
具体属于哪个派生类以及派生类的具体
内容
(
gdb
查看
指针
内容
),那么对于复杂项目的调试,配合VsCode的断点和单步调试功能(VsCode单步调试),如果能够实时
查看
当前
指针
指向
的所有内存信息,将大大提升debug的效率,本节将介绍如何实现。
软件是人思维的产物。智者千虑,必有一失,人的思维总有缺陷,反映到软件层面上就是程序 bug。程序 bug 的终极体现就是core dump,core dump 是软件错误无法恢复的产物。
我们经常见到的bug说“闪退、意外终止等”,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做corefile的文件。
通常情况下,corefile文件会包含了程序运行时的内存,寄存器状态,堆栈
指针
,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成的一个文件,许多的程序出错的时候都会产生一个corefile文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。
对于那些具有高级编程语言诸如: Ruby、Scheme、Haskell 等背景的人来说,学习 C 语言是具有挑战性的。除了纠结于 C 语言中像手动内存管理和
指针
等底层特性外,你必须在没有 REPL ( Read-Eval-Print Loop ) 的条件下完成工作。一旦你已经习惯于在 REPL 环境下进行探索性的编程,必须进行“编写-编译-运行”这样循环实在有点令人生厌。
最近我发现其实可以用
GDB
来作为 C 语言的伪 REPL。我一直尝试使用
GDB
作为学习 C 语言的工具,而不仅仅是用来调试 C 程序,事实上这非常有趣。
这篇文章我的目的就是向你展示
GDB
是一个非常好的学习 C
网易云课堂免费课程:《C++跨平台开发中的编译错误》
---------------------------------------------------------------------------
在C++中提供了this
指针
来访问对象自身。那么,在开发的时候我们一般会在什么情况下会用到this
指针
呢?
一种...