在本人的《C语言可变参数函数的实现方法》一文中,介绍了如何建立自己的可变参数函数。

下面继续介绍可变参数函数的实现原理。
在汇编语言程序设计中,详细介绍了子程序的实现思想:
(1)子程序只是一段代码的起始地址;
(2)调用子程序之前,主程序将一些数据存入栈中;
(3)子程序被调用后,从栈中取出数据;
(4)栈底为高地址,栈顶为低地址;
(5)入栈时栈顶指针向低地址方向移动,出栈时,栈顶指针向高地址方向移动。
那C函数各个参数入栈的顺序是怎样的?
我们用一个程序来测试一下参数入栈顺序
程序的代码为:
#include void TestOrder(int iFirst, int iSecond, int iThird){ printf("First: %ld", (unsigned long)&iFirst); printf("Second: %ld", (unsigned long)&iSecond); printf("Third: %ld", (unsigned long)&iThird);}void main(){ TestOrder(1, 2, 3);}
这是程序的某次运行结果:
First: 140724053717020Second: 140724053717016Third: 140724053717012
入栈时,由于机器的栈顶指针是从高地址向低地址移动。所以我们可以得出结论:
默认情况下,C语言的参数入栈,是从左往右,依次入栈。
因此,main函数调用TestOrder函数时,参数入栈的顺序为:
- 值“1”入栈;
- 值“2”入栈;
- 值“3”入栈。
TestOrder函数则直接通过栈的地址,获得传入参数,原理是这样的:
- 栈顶第一个元素的地址,就是iThird形参的地址;
- 栈顶第二个元素的地址,就是iSecond形参的地址;
- 栈顶第三个元素的地址,就是iFirst形参的地址。
如果函数的参数列表是固定的,上面的过程,由编译器帮我们完成,我们体会不到内部的细节。
如果函数的参数列表是可变的,上面的过程,编译器已经无能为力,必须由我们自己来完成。
这就是我们使用这套奇怪的标识符的原因了:
- va_list
- va_start
- va_arg
- va_end
本文先讲解C函数参数的实现原理,下文将详细解析这套奇怪的标识符。
谢谢!
#科技新星创作营#