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()释放指针。