C函数中的形式参数可以是基本类型变量名,构造类型变量名和指针类型变量名。对于不同的形式参数,其传递参数的方式不同,总体来说分成两种:按值传递和按地址传递。 当形参是基本类型变量名时,采用按值传递方式;当形参是指针类型变量名或者构造类型变量名时,采用按地址传递方式。 下面通过两个相似的程序说明二者的区别:
//程序一:按地址传递参数
#include <stdio.h>
swap(int *x,int *y){
int t=*x; *x=*y; *y=t;
}
main(){
int a=15,b=22;
printf(“a=%d\tb=%d\n”,a,b);
swap(&a,&b);
printf(“a=%d\tb=%d\n”,a,b);
}
/*//输出结果:
a=15 b=22
a=22 b=15
//程序二:按值传递参数
#include <stdio.h>
swap(int x,int y){
int t=x; x=y; y=t;
}
main(){
int a=15,b=22;
printf(“a=%d\tb=%d\n”,a,b);
swap(a,b);
printf(“a=%d\tb=%d\n”,a,b);
}
//输出结果:
a=15 b=22
a=15 b=22
可以看出,程序一实现了a和b的值的交换,而程序二并没有实现。 先看一下两个程序的栈帧内容有何差别: [
//程序一汇编代码片段:
main:
leal -8(%ebp), %eax //将ebp-8里面的内容作为地址放到eax中
mov1 %eax, 4(%esp) //作为参数传到esp+4的位置
leal -4(%ebp), %eax //ebp-4传给eax,a=15
mov1 %eax, (%esp)
call swap
ret
swap:
//以下是准备阶段
push1 %ebp
mov1 %esp, %ebp
push1 %ebx //ebx是被调用者保存
//以下是过程体
mov1 8(%ebp), %edx //R[ecx]<-M[&a]=15
mov1 (%edx), %ecx //把15送到了ecx中
mov1 12(%ebp), %eax //R[ebx]<-M[&b]=22
mov1 (%eax), %ebx //把22送到ebx中
mov1 %ebx, (%edx) //ebx中的22替换掉a=15,之后a=22
mov1 %ecx, (%eax) //ecx中的15替换掉b=22,之后b=15
//以下是结束阶段
pop1 %ebx
pop1 %ebp
ret
//程序二汇编代码片段:
main:
leal -8(%ebp), %eax
mov1 %eax, 4(%esp)
leal -4(%ebp), %eax
mov1 %eax, (%esp)
call swap
ret
swap:
//以下是准备阶段
push1 %ebp
mov1 %esp, %ebp
//以下是过程体
mov1 8(%ebp), %edx
mov1 12(%ebp), %eax
mov1 (%eax), 8(%ebp)
mov1 %edx, 12(%ebp)
//以下是结束阶段
pop1 %ebp
ret
对比图: [