C语言的变参
函数的变参实际上就是:C语言利用调用栈而提供的一种参数传递的机制。
一、调用栈
我们知道C语言的调用约定为__cdecl,它的特点为:所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈。要了解它的确切含义,就先看一下函数调用是发生了什么,假设有如下的程序:
1: #include    
2: #include    
3:     
4: void foo(int count, ...)   
5: {   
6:     va_list args;   
7:     int t = 0;   
8:     int i = 0;  
9:    
10:     va_start(args, i);  
11:    
12:     for (i = 0; i < count; ++i) {  
13:         t = va_arg(args, int);  
14:         printf("%d", t);  
15:     }  
16:   
17:     va_end(args);  
18: }  
19:    
20: int main(int argc, char * argv[]) 
21: {  
22:     foo(5, 1, 2, 3, 4, 5);  
23:     return 0; 
24: }  
25:  
      在这段代码中,定义了一个带变参的函数foo,第一个参数为变参的个数,然后在main函数中对其进行了调用。当我们在调用foo函数的时候,按照调用约定,栈如下图所示:
我们知道,栈是向低地址方向生长的,当调用foo时,先由右向左将参数如栈,最后将返回地址如栈,这个结构只有调用者知道,这是调用约定规定的。
二、被调用函数内部
进入foo函数以后,foo函数内部是对上图栈的结构一无所知,准确的来说是变参的部分一无所知。它只知道它被调用了,有一个参数为变参的个数。为了获取这些变参,我们可以通过宏va_start来获取参数列表,这个宏有一个参数指定了第一个变参在那个参数后面。通过上图我们可以看出,要获取第一个变参的地址必之它的地址在count参数的后面。
获取每一个参数是通过宏va_arg来进行的,它需要指定每个参数的类型。从这一点我们可以看出,foo函数真的对栈上的变参情况一无所知。这一点告诉我们,foo函数内部要想主动知道变参的个数,是不可能的。当然,你可以通过其它方式获知。而且,刚好要获取上面的每个参数的首地址,只需要进行这样的计算即可:第一个变参的地址 + sizeof(参数类型)。我都怀疑,参数的入栈顺序是因为方便取才从右边的参数先如栈的。
最后一个和变参相关的宏是va_end,它实际上是简单的将变参表的指针置为空。
三、总结
有了上面的知识以后,我们可以确切的回答一些和变参相关的问题了。比如,我以前考虑过的:
      1. 变参可以直接往下一层函数调用传吗? 
      显然不行,因为带变参的函数内部对变参一无所知(变参的个数和类型),也就无法直接向下传递了。但是,你可以将变参表的首地址传递下去。
2. 上面提到的获取变参的个数的问题。
      3. 可以定义变参函数为bar(…)的形式吗? 
      显然不行,因为这样的话就无法获取变参表的首地址了。而且,这也是ANSI C 不允许的。
本篇文章来源于:开发学院 http://edu.codepub.com   原文链接:http://edu.codepub.com/2010/1223/28251.php
 
                   
                   
                   
                   
                             
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   5070
					5070
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            