1.认识相关寄存器
eax:通用寄存器,保存临时数据,常用于返回值。
ebx:通用寄存器,保存临时数据。
ebp:栈底寄存器。
esp: 栈顶寄存器。
eip: 指令寄存器,保存当前指令的下一条指令的地址。
2.认识相关汇编命令
mov: 数据转移指令
push: 数据入栈,同时esp栈顶寄存器也要发生改变。
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变。
sub:减法命令。
add: 加法命令。
call:函数调用,①压入返回地址。②转入目标函数。
jump:通过修改eip,转入目标函数,进行调用。
ret:恢复返回地址,压入eip,类似pop eip 命令。
3.函数栈帧总结1.临时变量的形成是在函数正式被调用之前就形成了的。
2.形参实例化的顺序是从右向左的。
3.函数调用完毕,栈帧结构被释放。
4.临时变量具有临时性的本质:栈帧具有临时性。
5.调用函数是有成本的,成本体现在时间和空间上,本质是形成与释放栈帧有成本。
6.函数调用,因拷贝所形成的临时变量,变量和变量之间的位置关系是有规律的。
二 可变参数列表1.注意事项
可变参数必须从头到尾逐个访问。如果你在访问了几个可变参数之后想半途终止,这是可以的,但是,如果你想一开始就访问参数列表中间的参数,那是不行的。参数列表中至少有一个命名参数。如果连一个命名参数都没有,就无法使用 va_start 。这些宏是无法直接判断实际存在参数的数量。 这些宏无法判断每个参数的是类型。如果在 va_arg 中指定了错误的类型,那么其后果是不可预测的2.原理
先看看这几个宏的含义: 1. 可变参数列表对应的函数,最终调用也是函数调用,也要形成栈帧 2. 栈帧形成前,临时变量是要先入栈的,根据之前所学,参数之间位置关系是固定的 3. 通过上面汇编的学习,发现了短整型在可变参数部分,会默认进行整形提升,那么函数内部在提取该数据的时候,就要考虑提升之后的值,如果不加考虑,获取数据可能会报错或者结果不正确。#include三 命令行参数#include //查找最大数据。 int FindMaxDate(int num, ...) { va_list arg; //定义可以访问可变参数部分的变量,其实是一个char*类型 va_start(arg,num); //使arg指向可变参数部分 int max = va_arg(arg, int); //根据类型,获取可变参数列表中的第一个数据 for (int i = 0; i < num - 1; i++)//获取并比较其他的 { int curr = va_arg(arg, int); if (max < curr) { max = curr; } } va_end(arg);//arg使用完毕,收尾工作。本质就是讲arg指向NULL return max; } int main() { int max = FindMaxDate(5,1,2,5,4,9); printf("%dn", max); return 0; }
1.main函数也是可以带参数的。
#includeint main(int argc, char* argv[], char* envp[]) { int i = 0; for(i=0; i
argc: 是个整型变量,表示命令行参数的个数(含第一个参数)。
argv :是个字符指针的数组,每个元素是一个字符指针,指向一个字符串。这些字符串就是命令行中的每一个参数(字符串)。
envp :是字符指针的数组,数组的每一个原元素是一个指向一个环境变量(字符串)的字符指针。



