TUTORIAL: Pass Variable Number of Arguments to a C Function

  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6254
  • Loc: Seattle, WA

Post 3+ Months Ago

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:

CPP Code: [ Select ]
#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;
}
  1. #include <stdarg.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4.  
  5. int sum( int num, ... ) {
  6.  
  7.     va_list args;
  8.     va_start(args, num);
  9.  
  10.     int i, total = 0;
  11.     for( i = 0; i < num; ++i ) {
  12.         total += va_arg(args, int);
  13.     }
  14.  
  15.     va_end(args);
  16.  
  17.     return total;
  18. }
  19.  
  20. int main() {
  21.  
  22.     int total = sum(5, 1, 2, 3, 4, 5);
  23.     printf("Total: %d\n", total);
  24.  
  25.     return 0;
  26. }


How It Works


Let's look at the code line by line:

CPP Code: [ Select ]
#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.

CPP Code: [ Select ]
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.

CPP Code: [ Select ]
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.

CPP Code: [ Select ]
va_start(args, num);

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

CPP Code: [ Select ]
int i, total = 0;
for( i = 0; i < num; ++i ) {
    total += va_arg(args, int);
}
  1. int i, total = 0;
  2. for( i = 0; i < num; ++i ) {
  3.     total += va_arg(args, int);
  4. }

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.

CPP Code: [ Select ]
va_end(args);

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

CPP Code: [ Select ]
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!
Attachments:
MultipleArgumentsC.zip

(646 Bytes) Downloaded 457 times

Complete source code for the sum() example used in this tutorial.

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13504
  • Loc: Florida

Post 3+ Months Ago

I understand everything except this part.

CPP Code: [ Select ]
int sum( int num, ... ) {


Would this be valid ?

CPP Code: [ Select ]
int sum( ... ) {


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

Furthermore, is this valid ?

CPP Code: [ Select ]
int sum( int one, int two, ... ) {
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6254
  • Loc: Seattle, WA

Post 3+ Months Ago

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:
CPP Code: [ Select ]
int sum( int first, int second, int third, ... ) {
    va_list args;
    va_start(args, [b]third[/b]);
  1. int sum( int first, int second, int third, ... ) {
  2.     va_list args;
  3.     va_start(args, [b]third[/b]);

This tells va_start() where to look for the first unnamed argument.
  • wrostek
  • Born
  • Born
  • wrostek
  • Posts: 1

Post 3+ Months Ago

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.
  • genux
  • Graduate
  • Graduate
  • User avatar
  • Posts: 106
  • Loc: UK

Post 3+ Months Ago

nice post.. sometimes you do really need to have a undefined number of parameters to a function.
  • koehler
  • Born
  • Born
  • koehler
  • Posts: 2

Post 3+ Months Ago

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
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6254
  • Loc: Seattle, WA

Post 3+ Months Ago

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

C Code: [ Select ]
int main(int argc, char *argv[]) {
 
}
  1. int main(int argc, char *argv[]) {
  2.  
  3. }


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
  • koehler
  • Born
  • Born
  • koehler
  • Posts: 2

Post 3+ Months Ago

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?
  • jaqulin
  • Born
  • Born
  • jaqulin
  • Posts: 1

Post 3+ Months Ago

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".

C Code: [ Select ]
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;
}
  1. int sum( int num, ... ) {
  2.  
  3.     va_list args;
  4.     va_start(args, num);
  5.  
  6.     char buf[80];
  7.     for( i = 0; i < num; ++i ) {
  8.         buf[i]= va_arg(args, int);
  9.     }
  10.  
  11.     another function(num,buf[0],buf[1]);
  12.     va_end(args);
  13.  
  14.     return total;
  15. }

Post Information

  • Total Posts in this topic: 9 posts
  • Moderator: Tutorial Writers
  • Users browsing this forum: No registered users and 2 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.