Search code examples
cvariadic-functions

Using va_args without passing num (like printf)


The following is the most basic example I can come up with to pass variable-length args to a function:

int printme(int num, ...)
{
    va_list ap;
    va_start(ap, num);
    for (int i = 0; i < num; ++i) {
        char *arg = va_arg(ap, char *);
        printf("%d. %s\n", i + 1, arg);
    }
    va_end(ap);
    return 1;
}

int main(void)
{
    printme(2, "X", "YY");
}

However, notice that I am passing in the length as the first argument (or as any argument). Is it possible to use these va_ macros with something like a printf-ish function? For example, could I do something like this (without passing the number of args?

print2("Hello something %s %s", "Arg 1", "Arg 2");
print2("Hello something %s %s %s", "Arg 1", "Arg 2", "Arg 3");

If so, what would the function to receive that look like? And if it's not possible, how does printf implement it then?


Solution

  • If you only want to pass strings, it can be done quite easily by writing a function to parse the first argument like countargs(char*) that I've written here. It returns the number of arguments:

    #include <stdarg.h>
    #include <stdio.h>
    int printme(char* fmt, ...)
    {
        va_list ap;
        int num = countargs(fmt);
        va_start(ap, num);
        for (int i=0; i < num; ++i) {
            char* arg = va_arg(ap, char*);
            printf("%d. %s\n", i+1, arg);
        }
        va_end(ap);
        return 1;
    }
    
    int countargs(char* fmt)
    {
        int i, num = 0;
        if(strlen(fmt) < 2) 
        { 
            return 0;
        }
        for(i = 0; fmt[i+1] != '\0'; i++)
        {
            if (fmt[i] == '%' && fmt[i+1] == 's')
            {
                num++;
            }
        }
        return num;
    }
    
    int main(void)
    {
        printme("%s%s", "Stack", "Overflow");
    }