1. 程式人生 > 實用技巧 >c的可變引數(va_arg,va_list,va_start,va_end)

c的可變引數(va_arg,va_list,va_start,va_end)

首先是標頭檔案. <stdarg.h>

其次, 我們的目的是實現支援變長引數的函式, 但並不是說,這個函式引數可以全都是變的. 不行. 函式的引數列表中, 一定至少要有一個有name的引數. 比如printf, 它的定義是printf(const char * restrict format, ...);也是有restrict format這個有name的引數的. 變參正如printf顯示的那樣, 是...

好了, 怎麼用呢. 我們拿一個網上部落格的例子. 出處是深入C語言可變引數(va_arg,va_list,va_start,va_end)

#include <stdio.h>
#include <stdarg.h>

void print_args(int count, ...);

int main(int argc, char* argv[]) {
	print_args(5,1,2,3,4,5);
	return 0; 
}

void print_args(int count, ...) {
	int i, value;
	va_list arg_ptr;
	va_start(arg_ptr, count);
	for(i=0; i<count; i++) {
		value = va_arg(arg_ptr,int);
		printf("position %d = %d\n", i+1, value);
	}
	va_end(arg_ptr);
}

首先看函式的定義, 有一個有name的引數count, 除此之外就是變參...
要獲得變參, 首先需要定義一個va_list型別的變數, 這裡是va_list arg_ptr;. 這個型別的變數, 之後會遍歷獲取到所有的引數, 這個變數我們會一直用, 一直到引數解析完畢.
但這個變數使用前必須初始化, 我們看到是va_start(arg_ptr, count);, 這個函式實際上是一個巨集. 它需要兩個引數, 第一個是va_list型別的遍歷變數, 第二個引數是這個函式最後一個有name的引數, 這裡就是count. 但是va_start的作用是什麼呢?

The macro va_start initializes ap to point to the first unnamed argument.
讓它指向第一個unnamed的引數.
好了, 那麼怎麼獲得變參呢? 這就是value = va_arg(arg_ptr,int);

, 第一個引數自然是va_list型別, 第二個引數是指定型別, 這樣才知道它佔的記憶體大小, 才知道它佔了多少, 下一步該到記憶體什麼位置. 返回就會返回int型別的. 這個va_arg應該也是巨集.
最後必須在函式返回前呼叫va_end, K&R是這麼說的:
Finally, va_end does whatever cleanup is necessary.

好了再總結使用要點:

  • 標頭檔案是<stdarg.h>
  • 先定義va_list變數, 然後va_start它, 第二個引數是最後一個named引數
  • va_arg(va_list變數, 型別)解析引數, 返回就是我們呼叫的引數.
  • 最後用va_end釋放va_list變數.