gdb调试工具
熟练地掌握gdb调试工具是十分重要的,能够帮助我们加深对代码及相关概念的理解。部分指令如下:
指令 | 功能 |
---|---|
l(list) | 列出源代码 |
start | 进行单行调试 |
p | 打印某值 |
n | 继续执行下一行 |
s | 进入函数内部 |
bt | 查看函数堆栈 |
回车 | 继续刚才的命令 |
x/(数字)(类型)+地址 | 输出内存中的值,例如x/3d+地址 |
f +函数号 | 可查看当前函数中的变量值 |
内存管理
- 32位操作系统只能使用4G内存,地址总线32位(寻址空间32位)
- 64位操作系统,内存相比较32位足够多了。
其中,用户应用程序使用48位足够用(0x7fffffffffff);剩余的用于操作系统内核。
内存规划(这里只表示顺序,未体现大小) |
---|
系统内核 |
自由可分配 |
堆 |
数据段 |
代码段 |
几点解释:
- C语言语法不允许直接操作代码段
- 栈能够把程序执行过程中的全部状态记录下来,地址比较大;此外遵循先进后出原则,先进的地址大,后进的地址小。
- 操作系统和应用程序隔离开的好处:操作系统不会大量占用,避免机器卡住等等
指针
- 如果说变量只是一个代号,本质是内存。而指针保存的就是内存地址。
- 指针偏移运算,根据对应数据类型占几个字节(如在64位操作系统中,指针占8个字节,整型占4个字节)
- 数组本质也是指针类型,是指针常量
最开始可以通过调试简单的代码来更深入地理解指针和内存的内涵,如下面的简单例程。我们可以在gdb条件下,通过p &函数名;p &变量名;p *变量名等来查看内存地址或者存放数据等的信息。
#include <stdio.h>
int global=0;
int rect(int a, int b)
{
static int count=0;
count++;
global++;
int s=a*b;
return s;
}
int quadrate(int a)
{
static int count=0;
count++;
global++;
int s=rect(a,a);
return s;
}
int main()
{
int a=3;
int b=4;
int *pa=&a;
int *pb=&b;
int *pglobal=&global;
int (*pquadrate)(int a)=&quadrate;
//int s=quadrate(a);
int s=(*pquadrate)(a);
printf("%d\n",s);
}