In C programming, variadic function will contribute to the flexibility of the program that you are developing.
To understand this flexibility, let us start with a basic example.
If we like to add two numbers, we might write a code like this:
int addNumbers( int nNumberOne, int nNumberTwo ) { return nNumberOne + nNumberTwo; }.
If we like to add three number, we might write a code like this:
int addNumbers( int nNumberOne, int nNumberTwo, int nNumberThree ) { return nNumberOne + nNumberTwo + nNumberThree; }
As the number of digits that we need to add grows, we can keep adding more functions with appropriate number of arguments which represents the total number of numbers that we like to add.
But, that might get little bit cumbersome and hard to maintain.
Luckily in C programming, there is a easy way to do this using variadic function.
We typically use variadic function when we don’t know the total number of arguments that will be used for a function. Basically one single function could potentially have n number of arguments.
The concept of this variadic function is already used in several C’s in-built functions.
For example, in printf when you want to print one number, we do something like this.
printf(" the one number = %d", nOneNumber);
When you want to print two numbers, we still use the same printf function as shown below:
printf(" the first number = %d, the second number =%d ", nOneNumber, nSecondNumber);
If you look into the stdio.h, you can see that this was implemented using variadic functions.
This tutorial will explain the basics of how to use the concept of variadic functions inside your code.
C Variadic Macros
In order to use variadic functions we need to understand these macros:
va_list va_start va_arg va_end va_copy
All these macros are in the stdarg.h which should be included in your code as shown below:
#include <stdarg.h>.
The word variadic tells us that there is some kind of change or variation is involved here. The variation or change here is that we are dealing with unknown number of arguments for the function.
Variadic function has two parts: 1) mandatory arguments and 2) optional arguments.
Atleast one mandatory argument is required. The order is important in this case. So, you will have mandatory arguments first and then you will have optional arguments.
Now, I would advise you to look at those two printf functions. And if you understand it the same way I do, it seems like the first part is mandatory ( ” the one number = %d” ), the optional part comes second and it could be different ( nOneNumber ), depending on the situation you are in.
Common practice is to have some number that will tell us how many arguments there are or we look for stopping sign in our optional list.
va_list is used in situations in which we need to access optional parameters and it is an argument list. So, our list will contain some data that will be accessed after we declare our va_list and that is done like this:
va_list someArgumentPointer;.
In this situation, we need to mentions that our list will have appropriate data and that is the most interesting part of this technique. I will, later, explain how to implement that in function which doesn’t know how many elements are being invoked into it or the function that is looking for stopping sign within our string.
va_start will connect our argument list with someArgumentPointer, and we will need to say how many elements in our function we have. In order to use this we would write something like this:
va_start( someArgumentPoiner, numberOfElements );
This means that we have already declared our list and we have passed number of elements into our function.
va_arg is macro that will get our data which is currently connected to the argument list, and in order to achieve that task, we would need to know the type of our data. So, to do that we would write:
va_arg( someArgumentPointer, someType );
va_end is used in situations when we would like to stop using someArgumentPointer. One more situation in which we use this macro is when we need to reset our list position as well.
This macro will be used like this:
va_end( someArgumentPointer );.
va_copy is used in situations for which we need to save our current location, something like book marker. In another words, if you are in the situation in which you are advancing through argument list, but later you would need to rewind your current position to some previous state.
That could be done like this:
va_copy( va_list argumentDestination, va_list argumentSource );
In order to state that we have variadic function we need to state three dots as well, however that will be shown afterwards.
For an introduction on generic C Macros, this might help: How to Use C Macros and C Inline Functions with C Code Examples
C Variadic Example Code
The following simple example program will have three calls to our variadic function addingNumbers.
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> int addingNumbers( int nHowMany, ... ) { int nSum =0; va_list intArgumentPointer; va_start( intArgumentPointer, nHowMany ); for( int i = 0; i < nHowMany; i++ ) nSum += va_arg( intArgumentPointer, int ); va_end( intArgumentPointer ); return nSum; } int main( int argc, char** argv) { system( "clear" ); printf( "\n\n Variadic functions: \n\n" ); printf( "\n 10 + 20 = %d ", addingNumbers( 2, 10, 20 ) ); printf( "\n 10 + 20 + 30 = %d ", addingNumbers( 3, 10, 20, 30 ) ); printf( "\n 10 + 20 + 30 + 40 = %d ", addingNumbers( 4, 10, 20, 30, 40 ) ); printf( "\n\n" ); return EXIT_SUCCESS; }
In the above code, in order to know how many numbers we will pass to variadic function, we have the first number nHowMany, and don’t forget to add three dots. Those three dots will say that you are meddling with variadic function.
That could be achieved like this:
int addingNumbers( int nHowMany, … ).
Then we have sum declared and initialized to zero. As we have said earlier, we need to declare our argument list with va_list and that task will be achieved like this:
va_list intArgumentPointer;.
Then we need to connect our argument list and say how many elements we have in it.
va_start( intArgumentPointer, nHowMany );.
Now, we use “for” to advance through our argument list and add elements to the previous sum.
va_arg( intArgumentPointer, int );.
Then, as we have mentioned earlier, we need to state that we are closing our intArgumentPointer.
Finally, call our variadic function with multiple arguments:
addingNumbers( 2, 10, 20 ) addingNumbers( 3, 10, 20, 30 ) addingNumbers( 4, 10, 20, 30, 40 )
If you are C++ programmer, you can use implement similar concept using C++ variadic templates, which is available since C++ 11. If you are new to templates, this might help: C++ Template Functions Explained with an Example Program
Also, this is a good reference: Introduction to C++11 and C++14 with Example Code Snippet
Additional Ideas and Exercises to Explore
You can expand the above and create a function that will use double as data type and calculate the sum.
After that, create a function that will calculate average value and sum of unknown number of numbers.
Then, you might create your: and, or, xor, nor etc… functions. This group of functions could be useful in Calc, for example. Now, as you might figure out, it would be good to calculate how many arguments you are passing to variadic function from main function or you can pass the string to variadic function.
Then, if you have asked yourself, how do they create those programs that use switches from argument line, you could use argc to calculate, how many elements you have in your program and argv could be used to input those numbers that we need to add. So, next level could be to create the program that will work like ps command that you have in your terminal with various arguments.
A call from our main program could be:
addingNumbers( number, atoi( argv[1] ) );
All you need to do is to limit the number of inputs and some more juggling.
In the main function, that could be done like this:
if( argc < 2) { ... } if( argc > 6) { ... }.
You could also create your own printf function, and all you need to do is to input some strings into variadic function and test if you have some letters like: d, f, c, etc.
For that task, you might need some call of the function like this:
int ourPrint( char* cString, ... );
Later, you would need one character, let’s say that we are going to use ‘%’, as it is implemented in printf and scanf. If you don’t like this character, you could write your own version with some other character. However, this practice would lead to some compatibility issues.
So, there would be part in which you are reading characters. If those characters are in the input string and they are meant to be presented onto the screen, that task could be achieved, for example like this:
while( *ptrInputStringCopy ) { if( *ptrInputStringCopy != '%' ) { putchar( *ptrInputStringCopy ); ptrInputStringCopy++; continue; } ..
After, you could test if the next character is: int, char, float or boolean. That might be achieved with the next line and few more:
char cType = * ptrInputStringCopy; ptrInputStringCopy++; switch ( cType ) { case 'd' : int intValue = va_arg( argumentList, int ); printf( " %d ", intValue ); ++number_of_arguments; break; ...
And yes, I have used printf in this moment, because it is easier. Now, one would like to figure out if the number is long int or long float( which comes from double, … yeah now I get why they don’t use ‘i’ for integer, but ‘d’). In order to achieve that, you would need to have the test if the character is equal to ‘l’.
Something like this:
if( cType == 'l' ) { ... }
Apart from printf, you can also analyze scanf, fprintf, fscanf to see how variadic is implemented. If you like math, please check the source code of matheval.h which is done very well, and will give you lot of ideas on how to use variadic functions along with other core concepts.
Comments on this entry are closed.
The description of va_start() is wrong. The second argument to va_start() is the name of the last argument before the variable argument list, not the number of variable arguments.
THX for your observation…
@Anonymous May 31, 2017, 8:32 pm
“The second argument to va_start() is the name of the last argument before the variable argument list..”
This is the “official” definition which, however, lacks the most signifucant info: that is, this “second” argument is indeed the number of variable arguments that must have been passed form the caller to that last argument before the variable argument list.
and i must admit that i did, finaly, understand the whole mechanism of “Variadic Function” after redading this “wrong description” cited here!