C中的參數個數可變函數

 C中的參數個數可變函數
 C語言的調用規範(調用約定) 決定了C語言可以實現不定個數參數的函數。printf函數是一例子.
 
printf函數的原型:

int printf ( const char *format, ... );

  從函數原型可以看出,其除了接收一個固定的參數format以外,後面的參數用"..."表示。在C/C++語言中,"…"表示可以接受不定數量的參數,理論上來講,可以是0或0以上的n個參數。
 
1、可變參數函數的原型聲明:
type VAFunction(type arg1, type arg2, … );

參數可以分爲兩部分:個數確定的固定參數和個數可變的可選參數。函數至少需要一個固定參數,固定參數的聲明和普通函數一樣;可選參數由於個數不確定,聲明時用"..."表示。固定參數和可選參數公同構成一個函數的參數列表。

2、相關宏
  標準C/C++包含頭文件stdarg.h,該頭文件中定義瞭如下三個宏:
void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );

在這些宏中,va就是variable argument(可變參數)的意思;
arg_ptr是指向可變參數表的指針;
prev_param指可變參數表的前一個固定參數;
type爲可變參數的類型。
va_list也是一個宏,其定義爲typedef char * va_list,實質上是一char型指針。char型指針的特點是++、--操作對其作用的結果是增1和減1(因爲sizeof(char)爲1)。
 
   va_start宏可以取得可變參數表的首指針,這個宏的定義爲:
#define va_start ( ap, v ) ( ap = (va_list)&v + _INTSIZEOF(v) )

  顯而易見,其含義爲將最後那個固定參數的地址加上可變參數對其的偏移後賦值給ap,這樣ap就是可變參數表的首地址。其中的_INTSIZEOF宏定義爲:

#define _INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) & ~( sizeof( int ) - 1 ) )

  va_start(arg_ptr, argN):使參數列表指針arg_ptr指向函數參數列表中的第一個可選參數,說明:argN是位於第一個可選參數之前的固定參數,(或者說,最後一個 固定參數;…之前的一個參數),函數參數列表中參數在內存中的順序與函數聲明時的順序是一致的。如果有一va函數的聲明是void va_test(char a, char b, char c, …),則它的固定參數依次是a,b,c,最後一個固定參數argN爲c,因此就是va_start(arg_ptr, c)。
  
 
   va_arg宏的意思則指取出當前arg_ptr所指的可變參數並將ap指針指向下一可變參數,其原型爲:
#define va_arg(list, mode) ((mode *)(list =
(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

  va_end宏被用來結束可變參數的獲取,其定義爲:
#define va_end ( list )

  可以看出,va_end ( list )實際上被定義爲空,沒有任何真實對應的代碼,用於代碼對稱,與va_start對應;
 
 
一個簡單的例子

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

int max ( int num, ... )
{
 int m = -0x7FFFFFFF; /* 32系統中最小的整數 */
 va_list ap;
 va_start ( ap, num );

 for ( int i= 0; i< num; i++ )
 {
  int t = va_arg (ap, int);
  if ( t > m )
  {
   m = t;
  }
 }
 va_end (ap);
 return m;
}

int main ( int argc, char* argv[] )
{
 int n=max( 5, 5, 6 ,3 ,8 ,5); /*求5個整數中的最大值*/
  int m=max(7,1,5,78,6,56,8,2); /*求7個整數中的最大值*/
  printf("%d/t%d/n",n,m);
 return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章