作者:守望先生
ID:shouwangxiansheng
前言
变长参数,指的是函数参数数量可变,或者说函数接受参数的数量可以不固定。实际上,我们最开始学C语言的时候,就用到了这样的函数:printf,它接受任意数量的参数,向终端格式化输出字符串。本文就来探究一下,变长参数函数的实现机制是怎样的,以及我们自己如何实现一个变长参数函数。在此之前,我们先来了解一下参数入栈顺序是怎样的。
函数参数入栈顺序
我们可能知道,参数入栈顺序是从右至左,是不是这样的呢?我们可以通过一个小程序验证一下。小程序做的事情很简单,main函数调用了传入8个参数的test函数,test函数打印每个参数的地址。
编译成32位程序:
运行(不同的机器运行结果不同,且每次运行结果也不一定相同):
观察打印出来的地址,可以发现,从a到h地址值依次增加4。我们知道,栈是从高地址向低地址增长的,从地址值可以推测h是最先入栈,a是最后入栈的。也就是说,参数是从右往左入栈的(注:并非所有语言都是如此)。
但是如果将函数test参数b改为char 型呢?运行结果如下:
观察结果可以发现,b的地址并非是a的地址值加4,也不是在a和c的地址值之间,这是为何?这是编译器出于对空间,压栈速度等因素的考虑,对其进行了优化,但这并不影响变长参数的实现。
对于上面的情况,如果我们编译成64位程序又是什么样的情况呢?
运行结果如下:
通过观察可以发现,从参数a到f,其地址似乎是递减的,而从g到h地址又变成递增的了,这是为什么呢?事实上,对于x86-64,当参数个数超过6时,前6个参数可以通过寄存器传递,而第7~n个参数则会通过栈传递,并且数据大小都向8的倍数对齐。也就是说,对于7~n个参数,依然满足从右往左入栈,只是对于前6个参数,它们是通过寄存器来传递的。另外,寄存器的访问速度相对于内存来说要快得多,因此为了提高空间和时间效率,实际中其实不建议参数超过6个。
对于函数参数入栈顺序我们就了解到这里,但是参数入栈顺序和变长参数又有什么关系呢?
变长参数实现分析
变长参数实现
总结
领取专属 10元无门槛券
私享最新 技术干货