c语言参数传递和返回值及变量存储
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
unsigned int n;
void f1();
int f2(int,int);
void far f3();
main()
{
n=0;
f1();
n=f2(1,2);
f3();
}
void f1()
{
n=1;
}
int f2(int a,int b)
{
int c;
c=a+b;
return c;
}
void far f3()
{
n=10;
}
问题:
1程序运行时,n,a,b,c的段地址在哪个寄存器当中?
2全局变量的存储空间在什么段里?局部变量的存储空间在什么段里?
参数的存储空间在什么段里?函数的返回值又在什么段里?
3全局变量的存储空间在什么时候分配?什么时候释放?
4局部变量的存储空间在什么时候分配?什么时候释放?
5参数的存储空间在什么时候分配?什么时候释放?
6 函数f3 的在调用与返回上与函数f1 和f2 有何不同?
(unsigned int n;)
程序运行时变量n的段地址是放在ds寄存器里面的,这说明全局变量是放在内存里面的数据段,是而a,b,c等局部的变量都是放在栈段里面的,参数的存储位置也是栈段里头,而且是通过ax将参数压入栈中,然后用ss:bp 读取栈段里面的数据。
全局变量是在变量定义的时候就给变量分配了空间,全局变量空而局部变量则是在变量赋值过程中或者说是要用到的时候才分配的空间,在用完之后会马上释放,
参数的存储空间在调用函数之前会分配空间,函数调用完之后会马上释放。
f3 与f1,f2 调用的过成中f1,f2是段内调用,而f3 是段间调用.call指令上有明显差异,返回则相应的不同,一个是retf,一个则是ret。
程序二:
void f(void);
main ()
{
f();
f();
}
void f(void)
{
int n=0;
static int a=0;
n++;
a++;
printf("%d %d\n",n,a);
}
在main()里面是两条call调用指令
f()函数从201开始,push si,xor si,si,是将si保存在将si置零,这是n=0这条指令的汇编代码。
然后inc si (n++),而静态变量这是直接inc word ptr [0194] (a++)为什么没有将内存【0194】的内容置零的语句呢?难道是默认状态下内存【0194】里面的内容就是0吗?那么这样我将static int a=1;代码会怎么样呢?
经验证:
发现代码是一样的,那为什么会没有赋值的语句呢?但是可以肯定的n是通过si寄存器将值压入栈中,存储的地方是栈段,而a则是通过内存压入栈中,存储的地方是内存,而且函数每次调用的时候都没有赋值的操作,而si在函数调用都会有一次赋值操作这就是为什么静态变量每次用到的值都是最近使用过的值,那么静态变量的赋值操作到底在哪个地方呢? 因为根本就是没有赋值操作,对于静态变量编译器是这么处理的,编译器遇到static 标识符
时就会开闭内存空间并将其值放入内存中,静态变量有点像全局变量在定义。
全局变量是当做数据段在定义的
unsigned int a=1;
unsigned int b=1;
unsigned char c=1;
unsigned int a1=1;
unsigned long a2=1;
main()
{
a++;
b++;
c++;
a1++;
a2++;
printf("%d %d %d ",sizeof(int),sizeof(char),sizeof(long));
}
先看看int char long在tc2.0 下的长度分别是
那是不是相邻的呢?由
可知道是相邻的
其结果存储也是相同的:
不同的数据类型对数据预算会有一定的影响,如long 因为是四个字节,tc2.0 是双字节的,那么在进行加的操作如下:
对程序四:变量a,b和他们各项的数据项的存储空间是按照定义的时候预留下来的存储空间来分配,我们知道数据的位置,还必须知道数据的长度,而长度是编译器根据摸个约定来,分配的,比如说整形int 2个字节,而struct 相当于定义一个新的数据类型,像struct stu里面包含一个整形,两个字符型,一个长整形,struct把这个四个打包为一个数据类型,那么stu 就有8个字节了,关于a,b两个变量的个数据项是这么处理的
在main函数外面声明的stuct stu a 为全局变量,当然按照全局变量存储空间的分配方式分配存储空间,(在数据段里)而在main函数里面定义的b 则是按照局部变量定义,存放在栈段里面但是共同点是存储空间都是连续的。
程序五:
struct n{int a;int b; int c;};
int f(struct n);
struct n func(void);
main()
{
struct n a;
int b;
a=func();
b=f(a);
printf("%d",b);
printf("%d",f(func()));
}
int f(struct n a)
{
return (a.a+a.b)*a.c;
}
struct n func(void)
{
struct n a;
a.a=1;
a.b=2;
a.c=3;
return a;
}
Debug到1fa处:
下面我将解释下面的代码的意思,以便于我们对于这个程序的理解:
第一条和第二条语句是栈保护机制,用ss:bp便于访问栈里面的内容,sub sp ,06,是将栈顶指针向下移动6个字节,因为struct变量为六个字节,先把栈里面这些空间给预留下来,push si 将si压栈,lea bx [bp-6],这句话的意思是相当于汇编伪指令mov bx,offset [bp-6],[bp -6]里面的偏移量给bx其实也就是地址。
[bp-6]就是数组的地址。
Push ss 将ss压栈保存,
Push bx 将bx压栈保存//将偏移量压栈保存
此时栈里面的内容是由栈底到栈顶依次是,bp,si ,struct(int int int),ss,bx。
然后再调用子程序,func();call 266 将当前ip压栈jmp到0266的地方,
Push bp 将bp压栈将此时的sp给bp
然后sp减六
Mov word ptr [bp-06],0001
Mov word ptr [bp-04],0002
Mov word ptr [bp-02],0003
这三句是完成赋值操作,mov bx,0428,push ds push bx push ss push
此时栈里面的内容是bp,struct(int int int),ds,bx,ss,[bp-6],这是函数返回一个结构体的数据,也是用栈的机制,先开辟一段空间用来存放结构体的空间,然后在func里面又有struct 则又开辟一段空间并完成赋值操作。
然后经过块搬移同样的函数传给结构体的数据也是这么传的,可是上面这段代码我还有点没研究的透,基本上传递参数的操作。
用si di找到数据的位置然后通过快搬移操作,进行传值。