Variadic function in C/ C++


In this article we will be learning about the Variadic function in C and C++. Variadic functions are the functions that can take any number of arguments and is the foundation of common utilities like printf.

In this functions the number of arguments is not pre-defined during the declaration of the function.

Unlike normal functions where the number of arguments are specified during the function declaration , but here there is no requirement to declare number of arguments that the function is going to accept because the number of arguments are not fixed during the function declaration.

The number of arguments to be passed to the function solely depends upon the user while using the function call.

The above points will be clear from taking the example of most commonly used function in C that is printf() function . Now , while declaration we never how arguments are going to be passed in to this printf() . Thus , printf is a classic example of Variadic function.

So , the best thing about variadic function is that we can choose the number of arguments we need to pass to that function.

To access the function arguments and do further processing/ execution of function help from the library is taken.

All the functionalities to be used for this purpose are defined in the library <stdarg.h>.

The important macros that are often used in case of Variadic functions are :-
1.va_start: This helps in accessing the arguments of the of the Variadic function.
2.va_arg: This helps in accessing the next arguments of the of the Variadic function.
3.va_end: This ends the traversal we do in the list of arguments
4.va_list: This is the list storing all the required values.
5.va_copy: This helps in copying a source data to destination

Key Note:

  1. va_start intializes the va_list pointer to the first unnamed variable.
  2. There should be at least one named argument ,as the final named argument is being used by the va_start to intialize the list.

The functionalities of the above defined macros will be clear once we take an example.

Now lets see how to define a Variadic function.

Systax for the Variadic function.

return_type fun_name (const int *a, int b, …)
{
  Any code defined by user
}

The important to note in the above mentioned syntax is that the argument represented by 3 dots("...") tells us that it can accept any number of arguments but first two arguments are mandatory to be passed .

Steps in using the function properly:-

  1. The variable arguments are accessed sequentially in the order they are passed during the function call.
  2. A argument pointer variable type of pointer is feclared to iterate through the va_list , this can be done using the va_start (defined macro) , this helps in proper iteration through the va_list .
  3. va_arg can be used to access the next argument , this automatically points to the next argument that are being passed by the user during the function call.
  4. We can end when ever we want , this can be done by calling va_end.

How to call the variadic functions?

One thing is that before using the varaidic functions the same should be declared in the prototype of the function.

The calling of the variadic functions is similar to the calling of normal variadic functions .

During calling we pass the arguments as per our need , but the order of arguments is important.

During the call of the function each of the arguments that is a part of the variable argument list that we have undergoes special implicit conversions.

This implicit conversion is known as default argument conversion.

Note that since the data type of the variable arguments are not specified so we can infer that default argument promotions are done on the variable set of arguments to meet the requirements .

This means the char , short , bool are converted to int when required .

Similarly the float is upcasted to double.

This will be clear from the below mentioned snippet of code.

int example_func(int var, ...);
int test = example_func(2, 'd', true); // example_func is called with three integers: (2, 100, 1)

In the above mentioned example_func is an variadic function , here carefully observe that the var is defined as int so the rest of the variable arguments are upcasted to integer data type. The 'd' is converted to 100 as per ASCII equivalent of 'd' . Similarly the "true" is converted to 1 .

#include <iostream>
#include <stdarg.h>
 
using namespace std;
//we are definin the below function to calculate the average of the 
//of the numbers.
double calavg(int count, ...)
{
    double sum = 0;// intoalized to calculate the average
    
    va_list list;// the access the variable arguments 
    //that we just passed in the calling function.
    
    va_start(list, count);
     //The va_list is intialized using the va_start. 
   
    for (int arg=0; arg < count; ++arg)
         // The va_arg is used to get the parameters in the variable arguments
         //that we passed during function call
         // The first argument in the  va_arg is the va_list that
         // we are using
         // And The second argument is the type of the argument
         sum += va_arg(list, int);
         // note va_arg automatically points to next the argument of the function
 // this is used to end when our iteration is done
    va_end(list);
    return sum / count;// this is to calculate the average
}
 
int main()
{
    cout<< "The required averages are :- "<<endl;
     cout << calavg(7, 11, 52, 83, 47, 23, 66,78) << '\n';
    cout << calavg(8, 11, 42, 63, 47, 590,23,90,46) << '\n';
   
}

The output of the above code :-

The required averages are :- 
51.4286
114

In the above code , the function double calavg(int count, ...) is a variadic function because the number of arguments that are to be passed to the function are not fixed that is during the function definition it is not fixed what are the number of arguments this function is going to recieve .

Small version of how printf works:
miniprintf: our defined minimalistic function that mimics printf

#include<stdio.h>
#include<stdarg.h>
void minprintf(char *gmt,...);

int main(void)
{
    char *a="My world";
    miniprintf("%s",a);
    
    return 0;
}

void miniprintf(char *gmt,...)
{
    va_list la; 
    char *p,*sval;
    int ival;
    double dval;

    va_start(la,gmt);  
    
    for(p=gmt;*p;p++)
    {
        if(*p != '%')
        {
            putchar(*p);
            continue;
        }

        switch(*++p)
        {
            case 'd':
                ival = va_arg(la,int);
                printf("%d",ival);
                break;
            case 'f':
                dval = va_arg(la,double);
                printf("%f",dval);
                break;
            case 's':
                for(sval = va_arg(la,char *);*sval;sval++)
                    putchar(*sval);
                break;
            default:
                putchar(*p);
                break;
        }
    }
    va_end(la); /*to clean up when done */
}

The output of the above code :-

My world

With this article at OpenGenus, you will have the complete idea of Variadic function in C and C++. Enjoy.