va_arg、va_copy、va_end、va_start

存取變數引數清單。

type va_arg(
   va_list arg_ptr,
   type 
);
void va_copy(
   va_list dest,
   va_list src
); // (ISO C99 and later)
void va_end(
   va_list arg_ptr 
);
void va_start(
   va_list arg_ptr,
   prev_param 
); // (ANSI C89 and later)
void va_start(
   arg_ptr 
);  // (Pre-ANSI C89 standardization version)

參數

  • type
    要擷取之引數的型別。

  • arg_ptr
    指向引數清單的指標。

  • dest
    從 src中被初始化的引數清單的指標。

  • src
    要複製到 dest的引數使用的清單的指標。

  • prev_param
    第一個選擇性引數之前的參數。

傳回值

va_arg 會傳回目前的引數。 va_copyva_startva_end 不會傳回值。

備註

當函式接受變動的引數數量時,va_argva_copyva_endva_start 巨集提供可攜帶式的方法存取引數給函式。 有巨集的兩個版本: 在 STDARG.H 定義的巨集符合 ISO C99 標準;在 VARARGS.H 定義的巨集已被取代,但是在 ANSI C89 準則所撰寫之程式碼的回溯相容性 (Backward Compatibility)。

這些巨集假設函式採用固定數目的必要引數,後面接著不定數量的選擇性引數。 必要引數像給函式的參數一般宣告而且可以透過參數名稱存取。 選擇性引數可藉由 STDARG.H (或 VARARGS.H 的巨集在ANSI C89 標準所撰寫的程式碼) 的巨集擷取,當引數處理完成時,將指標在引數清單中的第一個選擇性引數,從清單中擷取引數,並重設指標。

定義在 STDARG.H,使用 C 標準巨集如下:

  • va_start 設定為 arg_ptr 中傳遞至函式的引數清單中的第一個選擇性引數。 arg_ptr 引數必須是 va_list 型別。 prev_param 引數是緊接在引數清單中的第一個選擇性引數之前要求參數的名稱。 如果 prev_param 被宣告為暫存器儲存類別,則巨集的行為是未定義。 在第一次使用va_arg 前,必須使用 va_start

  • va_arg 從arg_ptr給予地點的type 值,並藉由使用type的大小決定下一個引數的開始處,增加arg_ptr 以指向清單中的下一個引數。 va_arg 可以在函數中無限次使用以從清單中擷取引數的值。

  • va_copy 製作目前狀態的引數清單。 src 必須已經被以va_start初始化;它可能已經被以va_arg更新 呼叫,但是他絕對不能被以va_end重設。 由 va_arg 擷取自 dest 的下一個引數與從 src擷取的下一個引數相同。

  • 在擷取所有引數之後,va_end 重設指標為 NULL。 在函式傳回之前,必須呼叫使用 va_startva_copyva_end 的每個引數清單。

C++ 注意事項C++ 注意事項

在 VARARGS.H 的巨集來使用 ANSI C89 準則所撰寫之程式碼的回溯相容性已被取代而保留。在所有其他情況下,請使用STDARGS.H 裡的巨集。

使用 /clr (Common Language Runtime 編譯)編譯時,使用這些巨集的程式可能會由於在原生和 Common Language Runtime (CLR) 類型系統之間的差異產生未預期的結果。 請考慮此程式:

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

void testit (int i, ...)
{
    va_list argptr;
    va_start(argptr, i);

    if (i == 0)
    {
        int n = va_arg(argptr, int);
        printf("%d\n", n);
    }
    else
    {
        char *s = va_arg(argptr, char*);
        printf("%s\n", s);
    }
}

int main()
{
    testit(0, 0xFFFFFFFF); // 1st problem: 0xffffffff is not an int
    testit(1, NULL);       // 2nd problem: NULL is not a char*
}

請注意 testit 預期的第二個參數是 int 或 char*。 傳入的引數是 0xffffffff ( unsigned int,不是 int) 和 NULL (實際上是 int,不是 char*)。 當程式編譯機器碼時,會產生這個輸出:

  
  

然而,當您使用 /clr:pure 編譯程式時,型別不符是例外狀況引起的。 解決方法是使用明確轉換:

int main()
{
   testit( 0, (int)0xFFFFFFFF ); // cast unsigned to int
   testit( 1, (char*)NULL );     // cast int to char*
}

需求

標題: <stdio.h> 和 <stdarg.h>

取代標題: <varargs.h>

程式庫

C 執行階段程式庫的所有版本。

範例

// crt_va.c
/* Compile with: cl /W3 /Tc crt_va.c
 * The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_copy
 *      va_end              va_list
 */

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

double deviation(int first, ...);

int main( void )
{
    /* Call with 3 integers (-1 is used as terminator). */
    printf("Deviation is: %f\n", deviation(2, 3, 4, -1 ));

    /* Call with 4 integers. */
    printf("Deviation is: %f\n", deviation(5, 7, 9, 11, -1));

    /* Call with just -1 terminator. */
    printf("Deviation is: %f\n", deviation(-1));
}

/* Returns the standard deviation of a variable list of integers. */
double deviation(int first, ...)
{
    int count = 0, i = first;
    double mean = 0.0, sum = 0.0;
    va_list marker;
    va_list copy;

    va_start(marker, first);     /* Initialize variable arguments. */
    va_copy(copy, marker);       /* Copy list for the second pass */
    while (i != -1)
    {
        sum += i;
        count++;
        i = va_arg(marker, int);
    }
    va_end(marker);              /* Reset variable argument list. */
    mean = sum ? (sum / count) : 0.0;

    i = first;                  /* reset to calculate deviation */
    sum = 0.0;
    while (i != -1)
    {
        sum += (i - mean)*(i - mean);
        i = va_arg(copy, int);
    }
    va_end(copy);               /* Reset copy of argument list. */
    return count ? sqrt(sum / count) : 0.0;
}

Output

  

.NET Framework 對等用法

System::ParamArrayAttribute 類別

請參閱

參考

引數存取

vfprintf、_vfprintf_l、vfwprintf、_vfwprintf_l