某些情況下希望函數(shù)的參數(shù)個數(shù)可以根據(jù)需要確定。典型的例子有大家熟悉的函數(shù)printf()、scanf()和系統(tǒng)調(diào)用execl()等。那么它們是怎樣實現(xiàn)的呢?C編譯器通常提供了一系列處理這種情況的宏,以屏蔽不同的硬件平臺造成的差異,增加程序的可移植性。這些宏包括va_start、va_arg和va_end等。
---- 采用ANSI標準形式時,參數(shù)個數(shù)可變的函數(shù)的原型聲明是:
type funcname(type para1, type para2, ...)
---- 這種形式至少需要一個普通的形式參數(shù),后面的省略號不表示省略,而是函數(shù)原型的一部分。type是函數(shù)返回值和形式參數(shù)的類型。
---- 采用與UNIX System V兼容的聲明方式時,參數(shù)個數(shù)可變的函數(shù)原型是:
type funcname(va_alist)
va_dcl
---- 這種形式不需要提供任何普通的形式參數(shù)。type是函數(shù)返回值的類型。va_dcl是對函數(shù)原型聲明中參數(shù)va_alist的詳細聲明,實際是一個宏定義,對不同的硬件平臺采用不同的類型來定義,但在最后都包括了一個分號。因此va_dcl后不再需要加上分號了。va_dcl在代碼中必須原樣給出。va_alist在VC中可以原樣給出,也可以略去。
---- 此外,采用頭文件stdarg.h編寫的程序是符合ANSI標準的,可以在各種操作系統(tǒng)和硬件上運行;而采用頭文件varargs.h的方式僅僅是為了與以前的程序兼容。所以建議大家使用前者。以下主要就前一種方式對參數(shù)的處理做出說明。兩種方式的基本原理是一致的,只是在語法形式上有一些細微的區(qū)別。
---- va_start使argp指向第一個可選參數(shù)。va_arg返回參數(shù)列表中的當(dāng)前參數(shù)并使argp指向參數(shù)列表中的下一個參數(shù)。va_end把argp指針清為NULL。函數(shù)體內(nèi)可以多次遍歷這些參數(shù),但是都必須以va_start開始,并以va_end結(jié)尾。
---- 調(diào)用者在實際調(diào)用參數(shù)個數(shù)可變的函數(shù)時,要通過一定的方法指明實際參數(shù)的個數(shù),例如把最后一個參數(shù)置為空字符串(系統(tǒng)調(diào)用execl()就是這樣的)、-1或其他的方式(函數(shù)printf()就是通過第一個參數(shù),即輸出格式的定義來確定實際參數(shù)的個數(shù)的)。
---- 下面給出一個具體的例子。是采用了符合ANSI標準的形式的代碼。代碼中加了一些注釋,這里就不再解釋了。該例子已經(jīng)在VC/Windows XP、CC/AIX4.3.2.0、GCC/SUSE7.3環(huán)境下編譯并正常運行。
---- 1、演示如何使用參數(shù)個數(shù)可變的函數(shù),采用ANSI標準形式
#include < stdio.h >
#include < string.h >
#include < stdarg.h >
/* 函數(shù)原型聲明,至少需要一個確定的參數(shù),
注意括號內(nèi)的省略號 */
int demo( char *, ... );
void main( void )
{
demo("DEMO", "This", "is", "a", "demo!", "\0");
}
/* ANSI標準形式的聲明方式,括號內(nèi)的省略號表示可選參數(shù) */
int demo( char *msg, ... )
{
va_list argp; /* 定義保存函數(shù)參數(shù)的結(jié)構(gòu) */
int argno = 0; /* 紀錄參數(shù)個數(shù) */
char *para; /* 存放取出的字符串參數(shù) */
/* argp指向傳入的第一個可選參數(shù),
msg是最后一個確定的參數(shù) */
va_start( argp, msg );
while (1) {
para = va_arg( argp, char *); /*
取出當(dāng)前的參數(shù),類型為char *. */
if ( strcmp( para, "\0") == 0 )
/* 采用空串指示參數(shù)輸入結(jié)束 */
break;
printf("Parameter #%d is: %s\n", argno, para);
argno++;
}
va_end( argp ); /* 將argp置為NULL */
return 0;
}
轉(zhuǎn)自:
http://www.yourblog.org/Data/20041/2521.html