如何确定va_arg列表的结尾?

时间:2016-05-20 21:20:02

标签: c variadic-functions

我有一个功能foo(char *n, ...); 我需要获取并使用所有可选的char参数。 我有个想法使用

while(va_arg(argPtr, char) != NULL)
{
   ...
}

了解何时到达列表末尾。那么,它是否有效,如果在函数调用中我将foo(n, 't', 'm', '$', NULL);

va_arg会将NULL读为char吗? 或者可能有更常用的方法来确定列表的结尾,而不是添加NULL作为最后一个参数?

2 个答案:

答案 0 :(得分:7)

对于使用va_arg来确定给定调用传递的参数的数量或类型的函数,没有直接方式。

特别提出的建议方法:

while(va_arg(argPtr, char) != NULL)

不正确。 va_arg(argPtr, char)生成类型char的值,而NULL是空指针常量。 (NULL通常定义为0,它与空字符'\0'进行比较,但您不能依赖它。)

任何可变参数函数都必须让调用者指定参数的数量和类型。例如,*printf函数通过(非可变参数)格式字符串执行此操作。 POSIX execl*()函数需要一系列char*个参数;参数列表的末尾由调用者(char*)NULL标记。其他方法也是可能的,但它们几乎都依赖于参数中运行时给出的信息。 (你可以使用其他方法,例如全局变量。请不要。)

这会给调用者带来负担,以确保传递给函数的参数是一致的。该功能本身无法确认这一点。不正确的来电,例如printf("%d\n", "hello")execlp("name", "arg1")未定义的行为

还有一件事:您不能将va_argchar类型的参数一起使用。当您调用可变参数函数时,与, ...对应的参数将提升。窄于int的类型的整数参数将提升为intunsigned int,类型float的参数将提升为double。如果调用者传递类型为char的参数,则该函数必须调用va_arg(argPtr, int)

(在非常模糊的情况下,您不太可能遇到charunsigned int可以提升为char。只有当sizeof (int) == 1无符号且{{1}这意味着一个字节至少是16位。)

答案 1 :(得分:1)

基本想法会起作用。但是你已经以几乎肯定不会赢得的方式填写了细节。

当您使用可变参数时,通常的隐式转换规则不适用。相反,会发生默认参数提升,这意味着任何小于int / unsigned int的整数类型都会转换为其中一种 - 这不是唯一的促销,但这里唯一相关的 - 也意味着没有自动转换为您使用va_arg指定的任何类型。

这意味着:

  • 您不能使用va_arg(..., char),因为将char作为可变参数函数参数传递是不可能的。
  • 您不能将NULL作为可变参数函数传递,因为它的具体类型与实现有很大关系。现实类型包括intlongvoid *,还有其他不太现实但同样有效的类型。

你可以改变

while(va_arg(argPtr, char) != NULL)

while(va_arg(argPtr, int) != 0)

和电话

foo(n, 't', 'm', '$', NULL);

foo(n, 't', 'm', '$', 0);