[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > C/C++ > 正文
用C語言實現參數個數可變的函數
本文出自:中國計算機報2000年第13期 作者: 張文亮 (2001-06-13 15:11:54)
  採用C語言編程的時候,函數中形式參數的數目通常是確定的,在調用時要依次給出與形式參數對應
的所有實際參數。但在某些情況下希望函數的參數個數可以根據需要確定。典型的例子有大家熟悉的函數
printf()、scanf()和系統調用execl()等。那它們是怎樣實現的呢?

  C編譯器通常提供了一系列處理這種情況的宏,以屏蔽不同的硬件平台造成的差異,增加程序的可移
植性。這些宏包括vastart、vaarg和vaend等。

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

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

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

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

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

  type funcname(vaalist)

  vadcl

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

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

  調用者在實際調用參數個數可變的函數時,要通過一定的方法指明實際參數的個數,例如把最一個參
數置為空字符串(系統調用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!〞, 〞\0〞);

  }

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

  int demo( char msg, ... )

  {

  valist argp;

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

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

  char para;

  / 存放取出的字符串參數 /

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

  vastart( argp, msg );

  while (1) {

  para = vaarg( argp, char );

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

   if ( strcmp( para, 〞\0〞) == 0 )

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

  break;

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

   argno++;

  }

   va_end( argp );

   / 將argp置為NULL /

   return 0;

  }

  2.演示如何使用參數個數可變的函數,採用與UNIX System V兼容的方式

  #include 〈stdio.h〉

  #include 〈string.h〉

  #include 〈varargs.h〉

  / 函數原型聲明,括號內的類型valist在VC/Windows NT4.0可以保留,但在AIX和Linux下需要
去掉,即改成int demo( ) /

  int demo( valist );

  void main( void )

  {

   demo(〞This〞, 〞is〞, 〞a〞, 〞demo!〞, 〞\0〞);

  }

  / UNIX System V採用的聲明方式,括號內是vaalist,不是valist,而且vadcl面不需
要分號 /

  int demo( vaalist )

  vadcl

  {

  valist argp;

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

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

   char para;

  / 存放取出的字符串參數 /

  vastart( argp );

  / argp指向第一個可選參數 /

  while (1) {

  para = vaarg( argp, char );

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

   if ( strcmp( para, 〞\0〞) == 0 )

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

   break;

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

   argno++;

   }

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

  return 0;

  }

  表1
  ansi標準形式 unix systemⅤ兼容方式
頭文件 #include 〈stdarg.h〉 #include 〈varargs.h〉
va_start void va_start(argp, paran) va_list argp; void va_start(argp) va_list argp;
va_arg type va_arg(argp, type) va_list argp; type va_arg(argp, type) va_list argp;
va_end void va_end(argp) va_list argp; void va_end(argp) va_list argp;

(http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
 

★  樊強制作 歡迎分享  ★