C或C++为什么被设计成是从右向左处理函数参数?

这一直是一个迷惑人的问题,网上找竟然找不到答案,所以这是本文的目的。

C或C++的编译器被设计成按照从右向左的顺序来处理函数调用中的变元。但是编译器扫描变元的顺序

却是从左向右的。使用从左向右的处理顺序,编译器只需要一边扫描变元一边生成代码即可,但从右向左的顺

序却要编译器记住扫描过的所有变元。所以问题就来了,为什么C++设计者不设计成从左向右的函数参数处理

顺序呢?难道这是他们工作的疏忽吗,不是的。

原因是为了处理那些变元不固定的函数的调用。用个例子来说明,看下面的程序:

#include<iostream>
using namespace std;
int add(int count,...)//...指有不确定的变元个数
{
	int sum=0;
	int *p=&count+1;//p指向比count高一个单元的地址
	for(int i=0;i<count;i++)
	{
		sum+=*p;
		p++;
	}
	
	return sum;
}

int main()
{
	count<<add(3,1,2,3)<<endl;//sum=6
	return 0;
}
我们来看当main调用add时内存中的堆栈是怎么样的:

编译器按照从右向左的顺序把所有的参数压入栈中,当执行到p=&count+1的时候,使p指向比count高一个

字节的地址,然后for循环使接下的的三个数相加得到和sum。编译器之所以能够工作是因为编译器知道count的

地址,因为它比函数的返回地址高一个字节(栈的地址从上向下是逐渐增加的),所以可以直接引用它。

现在假设编译器不是按照从右向左的顺序把参数压入栈的,而是按照从左向右的顺序,堆栈的情况如下:

 现在如图所示,编译器将无法找到count的地址。因为编译器知道返回地址的地址,但不知道参数的个数

(因为不知道count等于多少),所以无法找到count的地址,也就不知道count等于多少。而要知道参数的个数就

需要知道count等于多少,所以编译器将陷入糊涂当中。这就是为什么C或C++要从右向左的顺序处理变元的原因了。

再来说一下变元的宏,在C或C++中,有些函数的变元计数是由第一个变元间接指定的。如下面的函数调用:

printf(“x = %d y = %d\n”,x,y);

printf的第一个变元是格式字符串,它必须包含调用中每个附加变元的变换码(以%开始的格式符)。上面有

两个变换码,表明在它的后面有两个要输出的数x和y。为了使访问有变长变元的参数列表更容易,C++提供了

va_list,va_start,va_arg,va_end这样几个宏。各个宏的功能如下:

va_list(p)=void *p;

va_start(p,count)=p=&count+1;

va_arg(p,int)=*((int *)p)++;

va_end(p)用于整理;

用宏把上面的程序改如下:

#include<iostream>
#include<cstdarg>
using namespace std;

int add(int count,...)
{
	int sum=0;
	va_list(p);
	va_start(p,count);
	for(int i=0;i<count;i++)
	{
		sum+=va_arg(p,int);
        va_end(p);
	}
    return sum;
}
int main()
{
	cout<<add(3,1,2,3)<<endl;
	return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值