Introduction

Note: The complete source code for the example in this tutorial can be downloaded at the end of the tutorial.

Note: Trying to do this in PHP? Check this out.

When declaring a function, the type and number of arguments are usually fixed at compile time. But sometimes it is necessary for a function to be able to accept a variable number of arguments unknown until run-time.

This tutorial will show you how to create a C function that can accept a variable number of arguments.

In A Nutshell

If you're simply looking for an example to go off of, I won't keep you waiting. Here's an example of a function sum() that adds up all of the integers passed to it and returns the sum:

#include <stdarg.h>
#include <stdio.h>
#include <stdarg.h>
 
int sum( int num, ... ) {
 
    va_list args;
    va_start(args, num);
 
    int i, total = 0;
    for( i = 0; i < num; ++i ) {
        total += va_arg(args, int);
    }
 
    va_end(args);
 
    return total;
}
 
int main() {
 
    int total = sum(5, 1, 2, 3, 4, 5);
    printf("Total: %d\n", total);
 
    return 0;
}

How It Works

Let's look at the code line by line:

#include <stdarg.h>

The stdarg library provides us with the va_list data type, as well as the macros va_start, va_arg, and va_end for manipulating the list of arguments.

int sum( int num, ... ) {

To declare the function, we use a triple dot (...) to signify that the function accepts a variable number of arguments. The first argument, num, is used to indicate how many arguments were passed into the function.

If we didn't want to use the first argument as a argument length specifier, we could have simply used the first argument as part of the numbered to be summed up, and then used some sort of special number (negative one, perhaps) as an indicator that the last argument has been reached.

va_list args;

va_list is a data type used by stdarg to hold the list of arguments passed into the function. Here we declare a variable called args.

va_start(args, num);

va_start is a macro used to initialize the argument list so that we can begin reading arguments from it.

int i, total = 0;
for( i = 0; i < num; ++i ) {
    total += va_arg(args, int);
}

Here, we loop through the list of arguments until we've read as many as specified in our first argument. va_arg is the macro used to read an argument from the list. It takes two parameters: the va_list object we created, args, and a data type. va_arg will return the next argument as this type.

va_end(args);

va_end is another macro that cleans up our args object for us when we're done using it.

return total;

Finally, we return the total we calculated in the function.

Conclusion

You should now know how to create a C function that accepts a variable number of arguments at runtime. This technique is particularly useful when creating wrapper functions for functions that already accept a variable number of arguments, such as printf(). This is demonstrated in my other tutorial, Writing a Custom printf() Wrapper Function in C.

I always welcome questions or feedback about this tutorial. Simply post a reply or PM me; I'm glad to help! Full code:

sum.c

/*
 * A function that accepts a variable number of
 * arguments at runtime.
 *
 * @author Jeff Linse
 * Created for the tutorial found at
 * [http://www.ozzu.com/cpp-tutorials](http://www.ozzu.com/cpp-tutorials)
 *
 * To compile with gcc:
 *     gcc -o sum sum.c
 *
 * To run:
 *     ./sum
 */

// included for standard output
#include <stdio.h>

// included to allow variable-length arguments
#include <stdarg.h>

// the first argument specified the number of
// arguments to follow
int sum( int num, ... ) {

	// declare the argument list
	va_list args;

	// initialize the argument list
	va_start(args, num);

	// loop through and add all arguments
	int i, total = 0;
	for( i = 0; i < num; ++i ) {

		// va_returns the next argument from the
		// list as the type specified (i.e. int)
		total += va_arg(args, int);
	}

	// clean up memory used by the argument list
	va_end(args);

	// return the total we calculated
	return total;
}

int main() {

	// sum up some integers
	int total = sum(5, 1, 2, 3, 4, 5);
	printf("Total: %d\n", total);

	return 0;
}

This page was published on

0

8 Comments

  • Votes
  • Oldest
  • Latest
JO

I understand everything except this part.

int sum( int num, ... ) {

Would this be valid ?

int sum( ... ) {

Or does there have to be a first argument followed by the ellipsis as the second ?

Furthermore, is this valid ?

int sum( int one, int two, ... ) {
add a comment
0
SP

I'm glad you asked, I forgot to elaborate on that.

Unfortunately, there must be at least one named argument before the ellipsis. You can specify as many named arguments as you'd like as long the ellipsis comes after all of them.

If specifying more than one named argument, the argument name passed as the second parameter to va_start() must be the last (right-most) named argument. For example:

int sum( int first, int second, int third, ... ) {
    va_list args;
    va_start(args, [b]third[/b]);

This tells va_start() where to look for the first unnamed argument.

add a comment
0
WR

I saw this nice introduction va_arg but I have a question a bit out of topic.
Its concerning trace statements. They are based on printf and I like to keep them in the released version. For performance reasons they should only dump to an in memory ring buffer. On crash it may be written to file or is somehow generated within the core file.
But the printf formatting takes too much runtime. Im looking for a way to collect only the parameters into an array and memcpy to the ring buffer. An off-line helper may make the formatting out of this capture later.
Is it possible to substitute printf for the release build by using va_arg? Or do I have to go down to assembler level to collect that information?

Thanks in advance for any hint
Wolfgang R.

add a comment
0
GE

nice post.. sometimes you do really need to have a undefined number of parameters to a function.

add a comment
0
KO

Hey, I was wondering if you can use this in the main() function. I need to accept parameters when the program is run. How would I go about doing this? Instead of the parameters being within the program, the parameters are when it is run at
./cw 1000 larry.cwo bob.cwo me.cwo
(ps. 1000 is cycles to run the program while the other 3 are the programs TO run)
How would you get the 3 programs (and their names) from this?

Thanks in advance for any replies!

Deana

add a comment
0
SP

That's actually the only way main() accepts arguments:

int main(int argc, char *argv[]) {

}

argc is the number of arguments passed to the program (including the name of the program itself

argv is an array of C-strings containing the arguments themselves.

http://www.bing.com/search?q=main+arguments

add a comment
0
KO

Alright. Awesome. So now if I wanted to get the size of those programs that were passed in the argument? I tried sizeof() but im new to c, and that only gave me the size of the type (char =1). Is there a way to get the size of the programs?

add a comment
0
JA

Nice Article!. Is there any way to pass the parameters extracted from va_list to be passed as arguments to another function dynamically?

for eg: In the below function I want to extract parameters from args
and pass it on to another_function depending upon "num".

int sum( int num, ... ) {

    va_list args;
    va_start(args, num);

    char buf[80];
    for( i = 0; i < num; ++i ) {
        buf[i]= va_arg(args, int);
    }

    another function(num,buf[0],buf[1]); 
    va_end(args);

    return total;
}
add a comment
0