Chinaunix首页 | 论坛 | 博客
  • 博客访问: 772140
  • 博文数量: 215
  • 博客积分: 291
  • 博客等级: 二等列兵
  • 技术积分: 1031
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-12 18:17
文章分类

全部博文(215)

文章存档

2016年(16)

2015年(16)

2014年(123)

2013年(60)

分类: 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,...)

{

i
阅读(985) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~