How to determine the end of va_arg list?

前端 未结 2 1444
情书的邮戳
情书的邮戳 2021-01-19 02:59

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(argP         


        
相关标签:
2条回答
  • 2021-01-19 03:12

    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.)

    0 讨论(0)
  • 2021-01-19 03:28

    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);
    
    0 讨论(0)
提交回复
热议问题