c語言中的可變參數編程


  在c語言中使用變長參數最常見的就是下面兩個函數了:

int printf(const char *format, ...);

int scanf(const char *format, ...);

  那他們是怎樣實現支持變成參數的呢?在使用變長參數的函數(這里假設是func)實現部分其實用到了stdarg.h里面的多個宏來訪問那些不確定的參數,它們分別是:

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);

  假設lastarg是func的最后一個具名參數,即在func函數定義中...之前的那個參數(在printf中lastarg是format),在func中首先定義一個變量:

va_list ap

  這個變量以后會依次指向各個可變參數。ap在使用之前必須用宏va_start初始化一次,如下所示:

va_start(ap, lastarg);

其中lastarg是func中的最后一個具名參數。然后就可以用va_arg來獲得下一個不定參數(前提是知道這個不定參數的類型type):

type next = va_arg(ap, type)

  最后就是用宏va_end來清理現場。

  下面我們來自己實現一個可變參數的函數:

 1 #include <stdio.h>
 2 #include <stdarg.h>
 3 
 4 void func(char *fmt, ...)
 5 {
 6     va_list ap;
 7 
 8     va_start(ap, fmt);
 9 
10     while (*fmt)
11     {
12         switch(*fmt)
13         {
14             case 'd':
15                 fprintf(stdout, "%d\n", (int)va_arg(ap, int));
16                 break;
17             case 'c':
18                 fprintf(stdout, "%c\n", (char)va_arg(ap, int));
19                 break;
20             case 's':
21                 fprintf(stdout, "%s\n", (char *)va_arg(ap, char *));
22                 break;
23             default:
24                 fprintf(stderr, "error fmt\n");
25         }
26         fmt ++;
27     }
28     va_end(ap);
29 }
30 
31 int main ( int argc, char *argv[] )
32 {
33     func("dcs", 10, 's', "hello");
34     return 0;
35 }               /* ----------  end of function main  ---------- */

  輸出結果:

10
s
hello

  可以看到上面的程序完成按我們的意願實現了變長參數的訪問,通過前面的fmt來控制下一個不定參數的類型。那這三個宏是怎樣實現對不定參數訪問的呢?下面來看看它們是怎么實現的:

  va_list實際就是一個指向各個不定參數的指針,由於參數的類型是不確定的,所以可以定義va_list為void *或者char *類型,即

#define va_list void *

  va_start就是將va_list指向函數最后一個具名參數lastarg后面的位置,這個位置就是第一個不定參數。

#define va_start(ap, lastarg) \
(ap = (va_list)&lastarg + sizeof(lastarg))

  va_arg獲取當前不定參數的值,根據當前參數的類型的大小移動指針指向下一個不定參數。

#define va_arg(ap, type) \
(*(type *)((ap += sizeof(type)) - sizeof(type)))

  va_end將指針清0。

#define va_end(ap) (ap=(va_list)0)

  本質上其實就是靠前面lastarg來控制不定參數的類型,va_list變量來指向不定參數的地址,然后根據lastarg一個一個的獲取不定參數。


免責聲明!

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



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