Stdarg.h

stdarg.h是C語言中C標準函式庫的標頭檔，stdarg是由standard（標準） arguments（參數）簡化而來，主要目的為讓函式能夠接收不定量參數。 C++的cstdarg標頭檔中也提供這樣的機能；雖然與C的標頭檔是相容的，但是也有衝突存在。

不定參數函式（Variadic functions）是stdarg.h內容典型的應用，雖然也可以使用在其他由不定參數函式呼叫的函式（例如，vprintf）。

 宣告不定參數函式 

不定參數函式的參數數量是可變動的，它使用省略號來忽略之後的參數。例如printf函式一般。代表性的宣告為:

int check(int a, double b, ...);

不定參數函式最少要有一個命名的參數，所以

char *wrong(...);

在C是不被允許的。在C，省略符號之前必須要有逗號；在C++，則沒有這種強制要求。
（雖然在C++中，這樣的宣告是合理的，但是這種寫法，因為沒有已命名的參數，使得va_start沒辦法抓到動態參數的正確起始點。）

 定義不定參數函式 

使用與聲明時相同的語法來定義:

long func(char, double, int, ...);

long func(char a, double b, int c, ...)
{
    /* ... */
}

在舊形式中可能會出現較省略的函式定義:

long func();

long func(a, b, c, ...)
    char a;
    double b;
{
    /* ... */
}

 stdarg.h数据类型 

 名稱  描述  相容va_list  用來保存宏va_arg与宏va_end所需信息  C89

 stdarg.h巨集 

 名稱  描述  相容va_start  使va_list指向起始的參數  C89va_arg  檢索參數  C89va_end  釋放va_list  C89va_copy  拷貝va_list的內容  C99

 存取參數 

存取未命名的參數，首先必須在不定參數函式中宣告va_list型態的變數。呼叫va_start並傳入兩個參數：第一個參數為va_list型態的變數，第二個参数為函式的動態參數前面最後一個已命名的參數名稱，接著每一呼叫va_arg就會回傳下一個參數，va_arg的第一個參數為va_list，第二個參數為回傳的型態。最後va_end必須在函式回傳前被va_list呼叫(當作參數)。(沒有要求要讀取完所有參數)

C99提供額外的巨集，va_copy，它能夠複製va_list。而va_copy(va2, va1)意思為拷貝va1到va2。

沒有機制定義該怎麼判別傳遞到函式的參數量或者型態。函式通常需要知道或確定它們變化的方法。共通的慣例包含:
 使用printf或scanf類的格式化字串來嵌入明確指定的型態。
 在不定參數最後的標记值(sentinel value)。
 總數變數來指明不定參數的數量。

 型別安全性 

有些C的实现，提供了对不定参数的扩展，允許編譯器檢查適當的格式化字串及標志(sentinels)的使用。如果沒有這种擴充，編譯器通常無從檢查傳入函式的未命名參數是否為所預期的型態，也不能转换它们为所需要的数据类型。因此，必須小心謹慎以确保正確性，因为不匹配的型態降到导致未定義行為(Undefined behavior)。例如，如果傳递空指针，不能仅仅写入NULL（可能实际定义为0），还要转化为（cast）适当的指针类型。另一个考慮是未命名参数的默认的类型提升。float將會自動的被轉換成double‧同樣的比int(整數)更小容量的參數型態將會被轉換成int或者unsigned int‧函式所接收到的未命名參數必須預期将被型態提升。

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

void printargs(int arg1, ...) /* 輸出所有int型態的參數，直到-1結束 */
{
  va_list ap;
  int i;

  va_start(ap, arg1); 
  for (i = arg1; i != -1; i = va_arg(ap, int))
    printf("%d ", i);
  va_end(ap);
  putchar('\n');
}

int main(void)
{
   printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
   printargs(84, 51, -1);
   printargs(-1);
   printargs(1, -1);
   return 0;
}

這個程式產生輸出:

5 2 14 84 97 15 24 48
84 51

1

 varargs.h 

POSIX定義所遺留下的標頭檔varargs.h，它早在C標準化前就已經開始使用了且提供類似stdarg.h的機能。MSDN明确指出这一头文件已经过时，完全被stdarg.h取代The macros defined in VARARGS.H are deprecated and exist solely for backwards compatibility. Use the macros defined in STDARGS.H unless you are working with code before the ANSI standard. 。這個標頭檔不屬於ISO C的一部分。檔案定義在单一UNIX规范的第二個版本中，簡單的包含所有C89 stdarg.h的機能，除了:不能使用在標準C較新的形式定義；你可以不給予參數(標準C需要最少一個參數)；與標準C運作的方法不同，其中一個寫成：

#include <stdarg.h>

int summate(int n, ...)
{
    va_list ap;
    int i = 0;

    va_start(ap, n);
    for (; n; n--)
        i += va_arg(ap, int);
    va_end(ap);
    return i;
}

或比較舊式的定義:

#include <stdarg.h>

int summate(n, ...)
    int n;
{
    /* ... */
}

以此呼叫

summate(0);
summate(1, 2);
summate(4, 9, 2, 3, 2);

使用varargs.h的函式為:

#include <varargs.h>

summate(n, va_alist)
    va_dcl /* 這裡沒有分號! */
{
    va_list ap;
    int i = 0;

    va_start(ap);
    for (; n; n--)
        i += va_arg(ap, int);
    va_end(ap);
    return i;
}

以及相同的呼叫方法。

varargs.h因為運作的模式需要舊型態的函式定義。

 參見 

可變參數函數

 參考 

Category:C标准库头文件