How to determine the end of va_arg list?

风格不统一 提交于 2019-12-01 23:06:52

问题


I have a function foo(char *n, ...); I need to get and use all of optional char parameters. I had an idea to use

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

to understand when I reach the end of the list. So, will it work, if in function call I'll do foo(n, 't', 'm', '$', NULL); ?

Will NULL be read as a char by va_arg? Or maybe there's a more common way to determine the end of list, without adding NULL as last parameter?


回答1:


There is no direct way for a function that uses va_arg to determine the number or type(s) of the arguments passed by a given call.

Your proposed method in particular:

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

is incorrect. va_arg(argPtr, char) yields a value of type char, while NULL is a null pointer constant. (NULL is commonly defined as 0, which compares equal to the null character '\0', but you can't rely on that.)

Any variadic function must have a way for the caller to specify the number and types of arguments. The *printf functions, for example, do so via the (non-variadic) format string. The POSIX execl*() functions expect a sequence of char* arguments; the end of the argument list is marked by the caller with (char*)NULL. Other methods are possible, but they almost all depend on information given at run time in the arguments. (You could use some other method, such as a global variable. Please don't.)

This places a burden on the caller to ensure that the arguments passed to the function are consistent. The function itself has no way to confirm this. Incorrect calls, like printf("%d\n", "hello") or execlp("name", "arg1") have undefined behavior.

One more thing: you can't use va_arg with an argument of type char. When you call a variadic function, arguments corresponding to the , ... are promoted. Integer arguments of types narrower than int are promoted to int or to unsigned int, and arguments of type float are promoted to double. If a caller passes an argument of type char, the function must invoke va_arg(argPtr, int).

(In very obscure circumstances that you're not likely to run into, char can be promoted to unsigned int. That can happen only if plain char is unsigned and sizeof (int) == 1, which implies that a byte is at least 16 bits.)




回答2:


The basic idea would work. But you've filled in the details in a way that almost certainly won't.

The usual implicit conversion rules don't apply when you're using variadic arguments. Instead, default argument promotions take place, which means that any integer type smaller than int/unsigned int gets converted to one of those -- that's not the only promotion, but the only one relevant here -- and which also means that there is no automatic conversion to whatever type you specify with va_arg.

This means that:

  • You cannot ever use va_arg(..., char), since it's impossible to pass a char as a variadic function argument.
  • You cannot ever pass NULL as a variadic function argument, since its concrete type is heavily implementation-dependent. Realistic types are int, long, void *, and there are loads of other less realistic but equally valid types.

You could change

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

to

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

and the call

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

to

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


来源:https://stackoverflow.com/questions/37356030/how-to-determine-the-end-of-va-arg-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!