可變參函式

可變參函式是採用C語言編程的時候,函式中形式參數的數目通常是確定的,在調用時要依次給出與形式參數對應的所有實際參數。

簡介

但在某些情況下希望函式的參數個數可以根據需要確定。典型的例子有大家熟悉的函式printf()、scanf()和系統調用execl()等。那么它們是怎樣實現的呢?

可變參函式的實現

C編譯器通常提供了一系列處理這種情況的宏,以禁止不同的硬體平台造成的差異,增加程式的可移植性。這些宏包括va—start、va—arg和va—end等。

使用這些宏有兩種不同的形式,二者在程式中包括的頭檔案不同,宏的定義也存在一些差別。這兩種方式對應的頭檔案和宏的聲明見表1。

採用ANSI標準形式時,參數個數可變的函式的原型聲明是:

type funcname(type para1, type para2, ...)

這種形式至少需要一個普通的形式參數,後面的省略號不表示省略,而是函式原型的一部分,type是函式返回值和形式參數的類型。

採用與UNIX System V兼容的聲明方式時,參數個數可變的函式原型是:

type funcname(va—alist)

va—dcl

這種形式不需要提供任何普通的形式參數,type是函式返回值的類型。va—dcl是對函式原型聲明中參數va—alist的詳細聲明,實際是一個宏定義,對不同的硬體平台採用不同的類型來定義,但在最後都包括了一個分號,因此va—dcl後不再需要加上分號了。va—dcl在代碼中必須原樣給出,va—alist在VC中可以原樣給出,也可以略去,但在UNIX上的CC或Linux上的GCC中都要省略掉。此外,採用頭檔案stdarg.h編寫的程式是符合ANSI標準的,可以在各種作業系統和硬體上運行,而採用頭檔案varargs.h的方式僅僅是為了與以前的程式兼容。所以建議大家使用前者。兩種方式的基本原理是一致的,只是在語法形式上有一些細微的區別。以下主要就前一種方式對參數的處理做出說明。

va—start使argp指向第一個可選參數。va—arg返回參數列表中的當前參數並使argp指向參數列表中的下一個參數。va—end把argp指針清為NULL。函式體內可以多次遍歷這些參數,但是都必須以va—start開始,並以va—end結尾。

調用者在實際調用參數個數可變的函式時,要通過一定的方法指明實際參數的個數,例如把最後一個參數置為空字元串(系統調用execl()就是這樣的)、-1或其他的方式。

下面給出一個具體的例子,前一部分是採用了符合ANSI標準形式的代碼,後一部分是採用了與UNIX System V兼容方式的代碼。代碼中加了一些注釋,這裡就不再解釋了。該例子已經在VC/Windows NT4.0、CC/AIX4.3.2.0、GCC/Redhat Linux 6.0環境下編譯並正常運行。

1.演示如何使用參數個數可變的函式,採用ANSI標準形式

#include 〈stdio.h〉

#include 〈string.h〉

#include 〈stdarg.h〉

/* 函式原型聲明,至少需要一個確定的參數,注意括弧內的省略號*/

int demo( char*, ... );

void main( void )

{

demo(″DEMO″, ″This″, ″is″, ″a″, ″demo!″, ″″);

}

/* ANSI標準形式的聲明方式,括弧內的省略號表示可選參數 */

int demo( char *msg, ... )

{

va—list argp;

/* 定義保存函式參數的結構 */

int argno = 0; /* 紀錄參數個數 */

char *para;

/* 存放取出的字元串參數*/

/* argp指向傳入的第一個可選參數,msg是最後一個確定的參數 */

va—start( argp, msg );

while (1) {

para = va—arg( argp, char ?);

/* 取出當前的參數,類型為char *. */

if ( strcmp( para, ″″) == 0 )

/* 採用空串指示參數輸入結束 */

break;

printf(″Parameter #%d is: %s\n″, argno, para);

argno++;

}

va_end( argp ); /* 將argp置為NULL*/

return 0;

}

相關詞條

熱門詞條

聯絡我們