For faster navigation, this Iframe is preloading the Wikiwand page for stdarg.h.

stdarg.h

stdarg.hC語言C標準函式庫標頭檔,stdarg是由standard(標準) arguments(參數)簡化而來,主要目的為讓函式能夠接收不定量參數。[1] 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指向起始的參數 C89
va_arg 檢索參數 C89
va_end 釋放va_list C89
va_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)意思為拷貝va1va2

沒有機制定義該怎麼判別傳遞到函式的參數量或者型態。函式通常需要知道或確定它們變化的方法。共通的慣例包含:

  • 使用printfscanf類的格式化字串來嵌入明確指定的型態。
  • 在不定參數最後的標记值(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取代[2]。這個標頭檔不屬於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因為運作的模式需要舊型態的函式定義。[3]

參見

[编辑]

參考

[编辑]
  1. ^ IEEE Std 1003.1 stdarg.h. [2009-07-04]. (原始内容存档于2009-04-11). 
  2. ^ 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.
  3. ^ 單使用者UNIX系統規範(Single UNIX Specification) varargs.h. [2007-08-01]. (原始内容存档于2008-06-18). 
{{bottomLinkPreText}} {{bottomLinkText}}
stdarg.h
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.

X

Get ready for Wikiwand 2.0 🎉! the new version arrives on September 1st! Don't want to wait?