0

I am learning stdarg.h in c i am trying to print all arguments passed to function without knowing how many arguments are there but yet i have not come up with solution, during this this happened, no matter what i pass to strtest. It always print 0. 1. 2. 3.

void strtest(char *fmt, ...){
    va_list argp;
    int i = 0;

    va_start(argp, fmt);

    while(va_arg(argp, char*))
        printf("%d\t", i++ );

    va_end(argp);
}

int main(int argc, char *argv[]){
    strtest("s");
    printf("\n");
    return 0;
}
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
valkiara
  • 9
  • 3

5 Answers5

5

There's no standard mechanism that will tell you the number of arguments passed to a varargs function. Functions like printf() work because they can determine the number of arguments by examining the format string.

keithmo
  • 4,893
  • 1
  • 21
  • 17
  • See this http://stackoverflow.com/questions/1688942/variable-arguments-in-c-how-to-get-values-with-a-generic-type for way to do it. I'm not sure this qualifies as standard but depending on environment make work for the OP. – JJF Nov 13 '15 at 20:13
  • @JJF That question is about argument types, not number of arguments. Is there a specific answer there that tells how to get the count? – Barmar Nov 13 '15 at 20:39
  • See the part with va_start(ap, count); for(i=0 ; i < count; i++) @Barmar – JJF Nov 13 '15 at 20:55
  • @JJF That requires passing a `count` argument before the varying arguments. – Barmar Nov 13 '15 at 20:57
  • Oh you're right @Barmar. You could count them similar to the MSDN sample I think https://msdn.microsoft.com/en-us/library/kb57fad8.aspx. Again I doubt it's standard but I'm pretty sure there is similar way with Linux. Cheers. – JJF Nov 13 '15 at 21:06
1

This is the definition of stdarg.h in the ISO 9899 WG14 n1256

The header <stdarg.h> declares a type and defines four macros, for advancing through a list of arguments whose number and types are not known to the called function when it is translated

You have to pass the number of arguments, and possibly the types as well, to the caller. This doesn't have to be done by directly passing the number of arguments, there are other methods such as the one used in printf.

Bobby Sacamano
  • 540
  • 4
  • 15
  • 1
    Or include a `NULL` sentinel. – Weather Vane Nov 13 '15 at 20:11
  • or parse something that functions like a format string (doesn't need to be a format string) – Grady Player Nov 13 '15 at 20:13
  • @WeatherVane The `NULL` sentinel only works if all the arguments are pointers of the same type. – Barmar Nov 13 '15 at 20:57
  • @Barmar I didn't think `NULL` was type-specific, but I posted an answer in which they are all the same type. – Weather Vane Nov 13 '15 at 21:03
  • @WeatherVane NULL is a void pointer, and there are some systems where void pointers have a different representation than an int pointer. http://c-faq.com/null/machexamp.html – Bobby Sacamano Nov 13 '15 at 21:05
  • I'm lost now why you are comparing chalk and cheese. http://stackoverflow.com/questions/3581585/whats-the-difference-between-a-null-pointer-and-a-void-pointer – Weather Vane Nov 13 '15 at 21:10
  • @WeatherVane Doesn't uncast NULL default to void* when you pass it as a variadic argument? If you have pointers to different types, the representation issues still exists. – Bobby Sacamano Nov 13 '15 at 21:11
  • What else could it possibly represent, since there is no other information? And why don't *all* pointers passed do likewise? – Weather Vane Nov 13 '15 at 21:13
1

Here is an example showing one way to pass an unknown number of arguments.

#include <stdio.h>
#include <stdarg.h>

void print (char *first, ...)
{
    va_list argptr;
    char *next;
    va_start (argptr, first);
    next = first;
    while (next) {
        printf ("%s\n", next);
        next = va_arg(argptr, char*);
        }
    va_end (argptr);
}

int main(void)
{
    print("hello","world", NULL);      // NULL as sentinel
    return 0;
}

Program output

hello
world

Perhaps you can adapt this to your needs using int arguments.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
0

You could pass a sentinel to the function like this

strtest("s", (char*)0);

such that the function can notice that it is at the end of the argument list.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
0

If you look at the man page for stdarg, va_arg includes this text

If there is no next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), random errors will occur.

Unless you call strtest with a NULL as the last argument, va_arg will just keep reading until it hits something that makes it stop. Think of what you are doing right now as equivalent to reading an array outside its bounds.

I'm surprised it was running 4 times no matter what though. I would have expected the count to be equal to the number of args you passed to strtest plus 2 or more.

hennign
  • 144
  • 1
  • 8