C语言函数调用时的传参操作在32位x86机器上依赖栈进行.而在x86_64的机器上使用了部分寄存器作为辅助,但如果参数过多,寄存器不够使用,此时也必须借助于栈操作实现传参.尽管C语言对函数传递参数的个数没有明确限制(依编译器实现而定:http://stackoverflow.com/questions/9034787/function-parameters-max-number),但过多的参数传递势必影响代码执行效率.
通常C语言函数传参是非常明确的,如下面这个函数:
int test(int a,float b,int *pointer);
注:以下例子均使用32位x86,gcc编译器说明.
但如果把数组或结构体作为参数传递呢?到底传递了多少参数,占用了多少栈空间?
typedef struct list{
int a;
int b;
int c;
int d;
int e;
}list;
int test1(int array[5]);
int test2(list listtest);
/*passing arguments test:array*/
#include
void array(int tmp[5]){
printf("%d\n",tmp[2]);
}
int main(void){
int test[]={1,2,3,4,5};
array(test);
}
编译成汇编代码,先截取main函数传参部分:
movl $1, -32(%ebp)
movl $2, -28(%ebp)
movl $3, -24(%ebp)
movl $4, -20(%ebp)
movl $5, -16(%ebp)
leal -32(%ebp), %eax
pushl %eax
call array
可以看到,在main函数中先将数组元素写入数组空间内,然后将数组地址(即元素a[0]的地址)保存在eax中,接着把eax压栈,最后调用array函数.再看看array函数:
array:
.LFB0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 8(%ebp), %eax
addl $8, %eax
movl (%eax), %eax
subl $8, %esp
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
nop
leave
ret
再来看结构体的例子:
#include
typedef struct list{
int a;
int b;
int c;
int d;
}list;
void test(list tmp){
printf("%d\n",tmp.b);
}
int main(void){
list tmp={.a=10,.b=20,.c=30,.d=40};
test(tmp);
}
movl $10, -24(%ebp)
movl $20, -20(%ebp)
movl $30, -16(%ebp)
movl $40, -12(%ebp)
pushl -12(%ebp)
pushl -16(%ebp)
pushl -20(%ebp)
pushl -24(%ebp)
call test
#include
typedef struct list{
int a;
int b;
int c;
int d;
}list;
void test(list *tmp){
printf("%d\n",tmp->b);
}
int main(void){
list tmp={.a=10,.b=20,.c=30,.d=40};
test(&tmp);
}