目录
运行模型
指令指针从下向上拨动
栈底指针从上到下拨动
CPU在执行指令的时候,也会操作内存
代码段
- 编译器把C语言代码编译成二进制的指令代码
- 程序运行的时候把二进制代码加载到代码段
- 代码段只读,不能被修改 ------> 安全
- CPU有一个指令指针,指向当前执行的指令
- CPU执行完一条指令后,在移动指令指针到下一个位置
- 指令条件跳转
int a = 3; // 局部变量都是定义在栈上的
if (a > 0) {
printf("if a > 0");
}
else {
printf("else called");
}
- 指令循环跳转
int i = 0;
while (i < 10) {
i++;
}
- 函数调用跳转, 函数返回跳转, 参数传递
int test_func(int a, int b) {
int c;
c = a + b;
return c;
}
int main(int argc, char** argv) {
int a = 3;
int b = 4;
int c = 0;
c = test_func(a, b);
system("pause");
return 0;
}
数据段
- 每个进程运行程序的时候都会分配一个数据段
- 数据段存放这个程序中所有的全局变量并为它分配好内存
- 内存一旦分配好,再也不能增加也不能减少
栈
- 操作系统会为每个进程分配一个栈
- 栈的大小有限,而且大小不大,所以不要在栈上分配大规模的内存块
- 栈底指针是往下拨动,内存就分配出来,往上拨动,内存回收
- 局部变量与函数的参数内存都分配在栈上 ------> 函数参数分配内存,按照从右到左的顺序
关键点
-
分配局部变量与参数 ------> 栈指针往下拨动变量所底需的大小分配出来
-
程序运行时的栈大小是有限的 ------> 不要定义大块内存的局部变量
-
函数调用
- 分配我们的参数的内存,从参数的右边到左边
- 将参数对应的内存做好数据初始化
- 将我们的下一条指令的位置,保存在栈里面
- 保存一下,我们栈底在调用函数之前的位置
- 把指令指针拨动到调用函数的地方
-
函数返回 ------> 那怕没有返回值,也会有一个隐式的 return
- 回收这个函数里面的局部变量,将我们的栈底拨回到我们没有调用函数前的地方
- 将我们的指令指针,拨回我们保存的下一条语句要执行的地方
- 保存我们的返回值,到一个地方 ------> VS是在EAX寄存器