C利用可变参数列表统计一组数的平均值,利用函数形式参数栈原理实现指针运算

//描述:利用可变参数列表统计一组数的平均值
#include <stdarg.h>
#include <stdio.h>

float average(int num, ...);//函数原型;即声明
float average2(int num, ...);//num个数
void add(int num, int x, int y, int z);
int main(void){
	int a=10;
	int b=20;
	printf("a地址:%p b地址:%p
",&a,&b);
	//宏来实现
	float aver = average(4, 10,20,30,40);
	printf("aver:%.2f
",aver);
	//调用指针可变参数来实现
	aver = average(4, 10,20,30,40);
	printf("aver2:%.2f
",aver);
	
	//调用add
	add(4,20,30,40);
	/*
	输出:说明依次压入栈中的顺序是 可能根据机器不同入栈先后也不同
	从下面输出结果看;高地址 n 先入栈;依次是x,y,最后z入栈
n地址:0x7ffff656d8ac 
x地址:0x7ffff656d8a8
y地址:0x7ffff656d8a4
z地址:0x7ffff656d8a0
	
	*/
	return 0;
}
float average(int val, ...)
{
	//定义一个va_list类型的变量用于访问可变参数类别
	va_list varlist;
	int count;
	float sum = 0;
	//初始化可变参数列表
	va_start(varlist,val);
	//通过循环获取可变参数列表的参数
	for(count=0;count<val;count++){
		sum += va_arg(varlist,int);
	}
	va_end(varlist);

	return sum/val;
}
/*描述:利用函数变量在栈中存储的原理来实现平均数
linux 中函数的参数如 int(int a,int b,int c) 依次是从 右边向左依次
压入栈空间的;所有可以定义一个指针来循环获取每一个可变参数的值
*/
float average2(int num,...)
{
	int* p = #
	float sum = 0;
	int i=1;
	for(; i<num;i++){
		sum += *(p+i);
	}
	return sum/num;
}
//扩展:使用函数栈的原理 利用指针来操作形式参数
void add(int num, int x, int y ,int z)
{
	//形式参数的地址
	printf("n地址:%p
",&num);
	printf("x地址:%p
",&x);
	printf("y地址:%p
",&y);
	printf("z地址:%p
",&z);
	
}

  

从上面来看;add函数参数入栈顺序 从左到右LInux 和Windows不一样

进一步发现,Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原因使得C语言函数参数入栈顺序为从右至左。
具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。
通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。
除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。
这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。
 
因此,C语言函数参数采用自右向左的入栈顺序,主要原因是为了支持可变长参数形式,
C语言中可变参数都是从左到右,所以不管你有多少个参数反正将最右面的那个压入栈底,最左面的参数出入栈顶。换句话说,如果不支持这个特色,
C语言完全和Pascal一样,采用自左向右的参数入栈方式
 
 
原文地址:https://www.cnblogs.com/wanglijun/p/8540642.html