2009年4月3日 星期五

C/C++ : 不定長度引數(Variable-length argument)

在定義函式時,有時我們並無法事先得知要傳遞的參數個數,這邊介紹不定長度引數(Variable-length argument)的使用為了要使用不定長度引數,您必須含入stdarg.h表頭檔案:
#include <stdarg.h>
不定長度引數使用幾個識別字來建立不定長度引數:

* va_list
一個特殊的型態(type),在va_start、 va_arg與va_end三個巨集(macro)時當作參數使用。

* va_start
啟始不定長度引數的巨集。

* va_arg
讀取不定長度引數的巨集。

* va_end
終止不定長度引數的巨集。

在宣告不定長度引數時,您在函式定義時使用 ... 表示將使用不定長度引數,而之前必須告知將傳遞幾個不定長度引數,例如:
void foo(int, ...);

在使用va_arg巨集取出引數內容時,您必須指定將以何種資料型態取出,例如:
va_arg(num_list, double);

下面這個程式示範如何使用不定長度引數:

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

void foo(int, ...);

int main(void) {
double x = 1.1, y = 2.1, z = 3.9;
double a = 0.1, b = 0.2, c = 0.3;

puts("三個參數:");
foo(3, x, y, z);

puts("六個參數:");
foo(6, x, y, z, a, b, c);

return 0;
}

void foo(int i, ...) {
double tmp;
va_list num_list;

va_start(num_list, i);

int j;
for(j = 0; j < i; j++) {
printf("%.1f\n", va_arg(num_list, double));
}

va_end(num_list);
}


而常與不定長度一起使用的function就是
int vsprintf (char * str, const char * format, va_list arg );
int vsnprintf(char *restrict s, size_t n, const char *restrict format,va_list ap);
下面這一個就是一個範例:
/* vsprintf example */
#include <stdio.h>
#include <stdarg.h>

// 不確定參數個數,format也是一個陣列,每一個對應一個變數,這一個例子是[%s,%d]
// 而...代表的就是後面的參數
void PrintFError (char * format, ...)
{
char buffer[256];
va_list args;
va_start (args, format); // format表示要arg是要以何種資料形態取出
// int vsprintf (char * str, const char * format, va_list arg );
// str表示要寫入的空間指標
vsprintf (buffer,format, args); // 把所有的字串塞到buffer所指的空間中
perror (buffer); // 把設定好的錯誤訊息字串列印出來,同時會依errno,列印出相對的錯誤訊息
va_end (args); // 結束不定參數個數函式的使用
}

int main ()
{
FILE * pFile;
char szFileName[]="myfile.txt";
int firstchar = (int) '#';

pFile = fopen (szFileName,"r");
if (pFile == NULL)
PrintFError ("Error opening '%s'\npFile:%d\n",szFileName,pFile);
else
{
// file successfully open
fclose (pFile);
}
return 0;
}

參考資料:
C Gossip: 不定長度引數(Variable-length argument)
vsprintf
vsprintf

沒有留言: