stdarg.h 簡介
stdarg.h是C語言中C標準函式庫的標頭檔,stdarg是由standard(標準) arguments(參數)簡化而來,主要目的爲讓函式能夠接收不定量參數。C++的cstdarg標頭檔中也提供這樣的機能;雖然與C的標頭檔是相容的,但是也有衝突存在。不定參數函式(Variadic functions)是stdarg.h內容典型的應用,雖然也可以使用在其他由不定參數函式呼叫的函式(例如,vprintf 等)。
stdarg.h的主要內容包括
typedef char * va_list;
#define _ADDRESSOF(v) ( &(v) )
#define _INTSIZEOF(n) ( (sizeof(n) +sizeof(int) - 1) & ~(sizeof(int)
- 1) )
#define va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
void va_copy(va_list dest, va_list src);
stdarg.h的用法
存取參數
存取未命名的參數,首先必須在不定參數函式中宣告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工具將C擴充允許編譯器檢查適當格式化字串及標兵(sentinels)的使用。如果沒有這個擴充,編譯器通常無從檢查傳入函式的未命名參數是否爲所預期的型態。因此,必須對點做出謹慎的正確性確認,型態沒有吻合爲未定義行爲(Undefined behavior)。舉個例,如果傳入NULL指標,首先就是不能寫入對應到適當指標型態但純粹NULL的指標。再者考慮預設參數應用到未命名參數。float將會自動的被轉換成double?同樣的比int(整數)更小容量的參數型態將會被轉換成int或者unsigned int?函式所接收到的未命名參數必須預期到會被轉換型態。
實例
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define LAST 5 //輸出的參數的個數
int examplestdary( int t , ... )
{
va_list ap ;
va_start( ap , t ) ;
int i ;
int tmp = 0 ;
for( i = 0 ; i < LAST ; i++ )
{
tmp = va_arg( ap , int ) ;
printf( "%d\t" , tmp ) ;
}
return 0 ;
}
int main()
{
examplestdary( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) ;
return 0;
}
小結
注意整個函數調用流程。首先,定義一個va_list類型的指針;然後va_start()指向最後一個確定的參數;接着,va_art()返回va_list類型指針的下一個元素;最後,va_end()釋放指針。