stdarg.h头文件详解

stdarg.h是C语言中C标准函数库的标头档,stdarg是由stdandard(标准) arguments(参数)简化而来,主要目的为让函数能够接收不定量参数。[1]C++的cstdarg标头档中也提供这样的机能;虽然与C的标头档是相容的,但是也有冲突存在。

不定参数函数(Variadic functions)是stdarg.h内容典型的应用,虽然也可以使用在其他由不定参数函数调用的函数(例如,vprintf)。

目录

   [隐藏] 
  • 1 声明不定参数函数
  • 2 定义不定参数函数
  • 3 stdarg.h数据类型
  • 4 stdarg.h宏
  • 5 存取参数
  • 6 型别安全性
  • 7 例子
  • 8 varargs.h
  • 9 参见
  • 10 参考

[编辑]声明不定参数函数

不定参数函数的参数数量是可变动的,它使用省略号来忽略之后的参数。例如printf函数一般。代表性的声明为:

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

不定参数函数最少要有一个命名的参数,所以

char *wrong(...); 

在C是不被允许的(在C++中,这样的声明是合理的)。在C,省略符号之前必须要有逗号;在C++,则没有这种强制要求。

[编辑]定义不定参数函数

使用相同的语法来定义:

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]

你可能感兴趣的:(stdarg.h头文件详解)