Functions with a Variable Number of Arguments in C
Variable Number of Arguments
Having reached this point, we have seen how to declare and define functions that accept (or not) a certain number of input parameters.
However, the more attentive reader will not have missed that there are functions, such as the library function printf, which can be invoked with a different number of arguments depending on the case.
Consider the following code snippet:
// We invoke the printf function with only one argument
printf("Hello\n");
// We invoke the printf function with two arguments
printf("The result is %d\n", 42);
// We invoke the printf function with three arguments
printf("The result is %d and the remainder is %d\n", 42, 1);
In the example above we invoked the printf function first with only one argument, then with two and finally with three arguments! Which would suggest that the printf function is almost an exception to the rule.
Actually, this is not the case. In fact, in C it is possible to define functions that accept a variable number of arguments through the features made available by the standard library. Let's see how to do it.
Function that accepts a variable number of arguments
First of all, to be able to define a function that accepts a variable number of arguments, we must use a special operator, ..., called ellipsis.
This operator must be positioned at the end of the list of formal parameters of the function. For example, the following function declaration is correct:
void function(int a, int b, ...);
In this case, the function function accepts two parameters of type int and a variable number of arguments of any type.
However, it is not possible to define a function that accepts a variable number of arguments without specifying at least one formal parameter. In fact, the following function declaration is not correct:
// Error:
// at least one formal parameter must be specified
void function(...);
Furthermore, the ellipsis cannot be used in other points of the formal parameter list. For example, the following function declarations are not correct:
// Error:
// The ellipsis cannot be placed at the beginning of the formal parameter list
void function(..., int a);
// Error:
// The ellipsis cannot be placed in the middle of the formal parameter list
void function(int a, ..., int b);
Ellipsis Operator
The ellipsis operator ... is a special operator in C that allows defining functions with a variable number of arguments. It must be positioned at the end of the formal parameter list and must be preceded by at least one formal parameter. It cannot be used in other points of the formal parameter list.
The correct syntax to define a function with a variable number of arguments is as follows:
return_type function(type1 a, type2 b, ...);
Once we have defined a function with a variable number of arguments, we can invoke it normally while paying attention to respect some conditions:
- The arguments corresponding to the explicit formal parameters must be provided in order and with the correct type.
- The arguments corresponding to the variable arguments can be provided in any order and with any type, but must be provided in sufficient number for the function to work correctly.
For example, suppose we want to declare a sum function that performs the sum of a certain number of integers. The declaration of the function could be as follows:
int sum(int n, ...);
In this case, n represents the number of arguments we want to sum. The sum function will therefore accept a variable number of arguments of type int.
At this point, we can invoke the sum function in this way:
int result = sum(3, 1, 2, 3);
With the first argument we indicate the number of arguments we want to sum, 3, and with the next three arguments we indicate the numbers to sum, 1, 2 and 3.
Now that we have seen how to declare and invoke a function with a variable number of arguments, let's see how we can implement it.
Library stdarg.h
To implement a function with a variable number of arguments, we must use some macros (we will see macros later) defined in the header file stdarg.h. This header file is part of the standard library of the C language and provides the necessary functionalities to handle variable arguments.
The main macros defined in stdarg.h are:
va_start: initializes an object of typeva_listto access the variable arguments.va_arg: retrieves the value of the next variable argument of a specified type.va_end: terminates access to the variable arguments.
Let's see how to use these macros to implement the sum function we declared earlier.
#include <stdio.h>
#include <stdarg.h>
int sum(int n, ...) {
int result = 0;
// Initializes an object of type va_list
va_list args;
va_start(args, n);
// Sums the variable arguments
for (int i = 0; i < n; i++) {
result += va_arg(args, int);
}
// Terminates access to the variable arguments
va_end(args);
return result;
}
int main() {
int result = sum(3, 1, 2, 3);
printf("The sum is: %d\n", result);
return 0;
}
As can be seen from the example, the implementation of the sum function consists of several steps:
- We declare a variable of type
va_listcalledargsto access the variable arguments. The typeva_listis a so-called opaque type, which means that it does not matter to know exactly how it is made, but only how to use it. In fact, all implementations of the C language can implementva_listin a different way. - We initialize
argswith the macrova_start, passing as the second argument the number of formal arguments that precedes the ellipsis. In this case, the number of formal arguments isn. Now it is clear why we cannot define a function with a variable number of arguments without specifying at least one formal parameter: we would not know where to start counting the variable arguments! - We retrieve the value of the next variable argument with the macro
va_arg, specifying the type of the argument we want to retrieve. In this case, we want to sum only arguments of typeint, so we passintas the second argument tova_arg. - Finally, we close access to the variable arguments with the macro
va_end.
There are other macros defined in stdarg.h, but the ones we have seen are the most common and the ones we need to implement a function with a variable number of arguments.
Recapping:
Macros to Handle Variable Arguments
The main macros defined in stdarg.h to handle variable arguments are:
-
va_start: initializes an object of typeva_listto access the variable arguments:va_list args; va_start(args, number_arguments); -
va_arg: retrieves the value of the next variable argument of a specified type:type argument = va_arg(args, type); -
va_end: terminates access to the variable arguments:va_end(args);
In Summary
In this lesson we introduced a very powerful mechanism provided by the C language to define functions with a variable number of arguments.
In particular we saw that:
- To define a function with a variable number of arguments, we must use the ellipsis operator
...at the end of the formal parameter list. - In addition to the ellipsis operator, we must declare at least one formal parameter.
- To implement a function with a variable number of arguments, we must use the macros defined in the header file
stdarg.h, in particularva_start,va_argandva_end. - The macro
va_startinitializes an object of typeva_listto access the variable arguments. - The macro
va_argretrieves the value of the next variable argument of a specified type. - The macro
va_endterminates access to the variable arguments. - The macros
va_start,va_argandva_endmust be used in this order to guarantee correct access to the variable arguments.