全部博文(215)
分类: LINUX
2013-11-27 09:15:19
C或C++的编译器是被设计成从右向左的顺序处理函数调用中的变元的。但是编译器扫描变元的顺序是从左向右的。使用从左路向右的顺序,编译器只需要一边扫 描变元一边生成代码即可,但从右向左的顺序却要编译器记住扫描过的所胡变元。为什么C++设计者不设计成从左向右的调用顺序呢,难道这是他们工作的疏忽 吗,不是的。
原因是为了处理那些变元不固定的函数调用。用个例子来说明,看下面的程序:
#include
Using namespace std;
int add(int count,…)//…是说有不确定的变元个数;
{
int i,sum=0;
int *p;
p=&count+1;//p指向比count高一个单元的地址
for(i=1;i<=count;i++)
sum+=*p++;
return sum;
}
int main()
{
cout<
return 0;
}
我们来看当main调用add的时候内存中的堆栈是怎么样的:
p
sum=0
i
返回地址
3(count)
1
2
3
sp
编译器从右向左的顺序把所有的参数压入规模当中,当执行p=&count+1的时候,使P指向count高一个字节,然后用下个for循环使接下
的的三个数相加得到和sum.编译器之所以能够工作是因为编译器知道count的地址,因为它位于函数的返回地址的高一个字节,所以可以直接引用它。
现在假设编译器不是从右向左的顺序把参数压入堆栈的,而是从左向右的顺序,堆栈的情况如下:
p
sum=0
i
返回地址
3
2
1
3(count)
sp
现在如图所示,编译器将无法找个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
#include
using namespace std;
int add(int count,...)
{