如何确定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_arg
与char
类型的参数一起使用。 当您调用可变参数函数时,将提升与, ...
对应的参数。 比int
更窄的类型的整数参数被提升为int
或unsigned 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
作为可变参数函数参数传递,因为它的具体类型与实现有很大关系。 现实类型是int
,long
,void *
,还有其他不太现实但同样有效的类型。
你可以改变
while(va_arg(argPtr, char) != NULL)
至
while(va_arg(argPtr, int) != 0)
和电话
foo(n, 't', 'm', '$', NULL);
至
foo(n, 't', 'm', '$', 0);