C語言中函數可變參數解析


  大多數時候,函數中形式參數的數目通常是確定的,在調用時要依次給出與形式參數對應的所有實際參數。但在某些情況下希望函數的參數個數可以根據需要確定。典型的例子有

大家熟悉的函數printf()、scanf()

  可變參數的實現:

  C語言頭文件stdarg.h提供了一個數據類型va-list和三個宏(va-start、va-arg和va-end),va—start使vp指向第一個可選參數。va—arg返回參數列表中的當前參數並使vp指向參數列表中的下一個參數。va
 
—end把vp指針清為NULL。函數體內可以多次遍歷這些參數,但是都必須以va—start開始,並以va—end結尾。用它們在被調用函數不知道參數個數和類型時對可變參數表進行測試,從而為訪問可變參數提供
 
了方便且有效的方法。va-list是一個char類型的指針,當被調用函數使用一個可變參數時,它聲明一個類型為va-list的變量,該變量用來指向va-arg和va-end所需信息的位置。
 
下面給出va_list在C中的源碼:
     typedef char * va_list; 

  采用ANSI標准形式時,參數個數可變的函數的原型聲明是:

      type funcname(type para1, type para2, ...) 
  這種形式至少需要一個普通的形式參數,后面的省略號不表示省略,而是函數原型的一部分,type是函數返回值和形式參數的類型。
 
  調用者在實際調用參數個數可變的函數時,要通過一定的方法指明實際參數的個數,例如把最后一個參數置為空字符串。
  
  下面給出一個具體的例子:
求n個數的和:
int Sum(int n,...)
{
    int i = 0,sum = 0;
    va_list vp; 
    va_start(vp,n); //va—start使vp指向第一個可選參數
    for (i=0; i<n; i++)
    {
        sum +=va_arg(vp,int); 
    }
    va_end(vp); //va—end把vp指針清為NULL。
    return sum;
}

printf函數實現:(此處只實現了基本類型的打印)

 1 void my_print(const char *format,...)
 2 {
 3     char c = 0;
 4     va_list vp; 
 5     va_start(vp,format); //vp指向第一個可選參數
 6     while (*format)
 7     {
 8         c = *format;
 9         switch (c)
10         {
11         case '%':
12             {
13                 char cc = *(++format);
14                 switch (cc)
15                 {
16                 case 'd':
17                     {
18                         char str[50];
19                         int  n = va_arg(vp,int); //va—arg返回參數列表中的當前參數並使vp指向參數列表中的下一個參數。
20                         char *string = _itoa(n,str,10); //把整數轉為字符串
21                         print_str(string);
22                     }
23                     break;
24                 case 'f':
25                     {
26                         char str[50];
27                         double f = va_arg(vp,double);//va—arg返回參數列表中的當前參數並使vp指向參數列表中的下一個參數
28                         char *string = _gcvt(f,10,str);//將浮點型數轉換為字符串,取四舍五入
29                         print_str(string);
30                     }
31                     break;
32                 case 'c':
33                     putchar(va_arg(vp,char));
34                     break;
35                 case 's':
36                     {
37                         char *string = va_arg(vp,char*);
38                         print_str(string);
39                     }
40                     break;
41                 default:
42                     break;
43                 }
44             }
45             break;
46         default:
47             putchar(c);
48             break;
49         }
50         format++;
51     }
52  va_end(vp);
53 }

理解可變參數很重要的是要理解函數棧幀的創建與銷毀,里面涉及到參數是如何壓棧,這方面內容在前面的博客:http://www.cnblogs.com/zhonglongbo/p/8392026.html

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM