三個宏的使用va_arg()、va_start()和va_end()
上述的宏原型如下所示:
type va_arg(va_list argptr, type); void va_end(va_list argptr); void va_start(va_list argptr, last_parm);
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) //類型n的大小,這是考慮了字節對齊 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一個不定參數地址 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一個參數地址 返回當前ap指向的值,並且增加ap #define va_end(ap) ( ap = (va_list)0 ) // 將指針置為無效
總結:讀取可變參數的過程其實就是堆棧中,使用指針,遍歷堆棧段中的參數列表,從低地址到高地址一個一個地把參數內容讀出來的過程.
3,不定參數函數有個限制,就是不定參數的列表必須在整個函數的參數列表的最后。
我們不可以定義如下的函數:
void func(int a, ……, int c)
所有類型固定的參數都必須出現在參數列表的開始。
在設計具有不定參數列表的函數的時候,我們有兩種方法來確定到底多少參數會被傳遞進來。
方法1是在類型固定的參數中指明后面有多少個參數以及他們的類型。printf就是采用的這種方法,它的format參數指明后面每個參數的類型。
方法2是指定一個結束參數。這種情況一般是不定參數擁有同樣的類型,我們可以指定一個特定的值來表示參數列表結束。
#include <stdio.h> #include <stdarg.h> #include <string.h> int sumi(int c, ...) { va_list argptr; va_start(argptr, c); //初始化變元指針 int sum = c; c = va_arg(argptr, int); //作為下一個參數類型的參數類型,返回不定參數 //c保存第一個不定參數 printf("%d\n", c); while(0 != c) //末尾特定字符指示結束 { sum = sum + c; c = va_arg(argptr, int); } va_end(argptr); return sum; } double sum_series(int num, ...) { double sum = 0.0, t; va_list argptr; va_start(argptr, num);//初始化變元指針 while (num--) { t = va_arg(argptr, double); sum = sum + t; } va_end(argptr); return sum; } int main() { int i = sumi(1,2,3,4,5,6,7,8,9,0); printf("%d\n", i); double d = sum_series(4, 1/3.0, 1/4.0, 1/5.0, 1/6.0); printf("%f\n", d); return 0; }
mutian@mutian:~/soft$ ./a.out
2
45
0.950000
