概述
调试
*1 使用GDB和其他工具进行调试
*2 断言
*3 内存调试
@1,OS分配给程序的内存一般都会比程序实际需要使用的大一些。如果非法内存访问
出现在这部分内存区域内,硬件就可能检测不到。
如果想捕捉到数组访问方面的错误,最好增加数组元素的大小,因为这样同时也增加
错误的大小。如果只是在数组的结尾之后读取一个字节,我们很有可能看不到有错误
发生,因为分配给程序的内存大小会取整到OS的特定边界,一般分配给内存大小以8K
为单位递增。
gcc -Wall -pedantic -ansi 这些选项将启动许多警告和其他检查来检验程序是否符合
C 语言标准。
@2,程序的受控执行
-- 较复杂的调试器可以在源代码级别查看程序的比较详细的状态信息。GDB就可以!
-g 标志,它将使用特殊版本的C语言标准库以提供库函数中的调试支持。
调试信息的加入将使可执行程序的长度成倍增加。调完后,最好将调试信息从程序的
发行版本中删除。
你可以用命令 strip <file> 将可执行文件中的调试信息删除而不需要重新编译程序。 debug3.c
#include <stdio.h>
#include <stdlib.h>
struct Node {
char str[4096*2];
int id;
};
struct Node p[5] = {
{"abc", 5},
{"bcd", 3},
{"cde", 2},
{"def", 4},
{"efg", 1},
};
void swap(struct Node* a1, struct Node* a2) {
struct Node temp = *a1;
*a1 = *a2;
*a2 = temp;
}
void bubble_sort (int len) {
int i, j;
for(i = 1; i < len; i++) { // len-1次就行
for(j = 0; j < len; j++) {
if(p[j].id > p[j+1].id) swap(&p[j], &p[j+1]);
}
}
}
int main() {
bubble_sort(5);
int i;
for(i = 0; i < 5; i++) {
printf("%dn", p[i].id);
}
return 0;
}
@3, 使用 gdb 进行调试
$ gcc -g -o debug3 debug3.c
$ gdb debug3
$ help
gdb 本身是一个基于文本的应用程序。gdb 直接按下回车键再次执行最近执行过的命令。
(gdb) run
Starting program: /home/hp/acm/debug3
Program received signal SIGSEGV, Segmentation fault.
0x00000000004006bc in bubble_sort (len=5) at debug3.c:24
24 if(p[j].id > p[j+1].id) swap(&p[j], &p[j+1]);
(gdb) backtrace
#0 0x00000000004006bc in bubble_sort (len=5) at debug3.c:24
#1 0x0000000000400738 in main () at debug3.c:30
(gdb) bt
#0 0x00000000004006bc in bubble_sort (len=5) at debug3.c:24
#1 0x0000000000400738 in main () at debug3.c:30
(gdb) where
#0 0x00000000004006bc in bubble_sort (len=5) at debug3.c:24
#1 0x0000000000400738 in main () at debug3.c:30
(gdb)
[因为在编译程序的时候添加了 gcc -g] 所以能够看到程序失败所停的位置。
backtrace 是桟跟踪,能够看到程序是怎么达到这里的!
这个程序比较简单,所以调试信息比较少。
gdb在停止程序时,给出的信息以及从跟踪桟得到的信息可以让我们看到函数参数的取值。
(gdb) print j
$1 = 4
(gdb) print p[3].id
$2 = 1
(gdb) print p[3]
$3 = {str = "efg", '