如何确定va_arg列表的结尾?

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

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

了解何时到达列表末尾。 那么,它会起作用吗,如果在函数调用中我会做foo(n, 't', 'm', '$', NULL);

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

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

您提出的方法特别是:

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

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

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

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

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

(在你不太可能遇到的非常模糊的情况下, char可以被提升为unsigned int 。只有当plain char是unsigned且sizeof (int) == 1才会发生这种情况,这意味着一个字节至少为16位。)

基本的想法是有效的。 但是你已经以几乎肯定不会的方式填写细节。

当您使用可变参数时,通常的隐式转换规则不适用。 相反, 默认参数促销发生,这意味着任何小于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);