Friday, Jan 19th

Last update12:59:40 PM GMT

Variadic Functions

Write e-mail

The term may sound a bit new to you but it is not. You have been using at least one variadic function so often without realising how it works, and that variadic function is printf().

argaiv1077

Variadic functions are those functions that can accept variable number of arguments, but at least one argument is required. As I told you earlier, printf() is one such function for which at least one format specifier (%d,%u,%s.... etc) is the required argument and what follows thereafter are optional arguments.

If we see the included header stdio.h, we see the declaration of printf as printf (const char *, ...).

To use a variadic function, it is mandatory to include stdarg.h. Thankfully stdio.h that we unknowingly always include in a C program also has that header file already included so we dont actually require to include stdarg.h explicitly. For C++, the corresponding header is cstdarg.h.

To create a variadic function, an ellipsis (...) must be placed at the end of a parameter list. Inside the body of the function, a variable of type va_list must be defined. Then the macros va_start(va_list, last fixed param), va_arg(va_list, cast type),va_end(va_list) can be used.

  • va_list here is the complete list of arguments.
  • va_start is used to initialise a pointer to the start of variable list of arguments after the fixed arguments.
  • va_arg is used to advance the va_arg pointer to subsequent arguments along with required casting as well.
  • va_end denotes the end of variable argument list.

Let us put all this into an example:

#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double sum= 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(i=0; i<count; j++)
sum+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return (sum/count);
}

This function computes average of any no. of arguments supplied to it. Note that the function does not know the number of arguments or their types. The above function requires that the types be double, and the number of arguments is passed in the first argument. In other cases, like in printf, the number and types of arguments are figured out from the format specifiers (number of format specifiers and type of format specifier, i.e, %d,%u,%s etc).

Note: In the variable-length part of variable-length argument lists, the old "default argument promotions'' apply: arguments of type float are always promoted (widened) to type double, and types char and short int are promoted to int. Therefore, it is never correct to invoke va_arg(argp, float), instead you should always use va_arg(argp, double). Similarly, use va_arg(argp, int) to retrieve arguments which were originally char, short, or int.

In any case, it depends on the programmer to actually supply the correct information. If fewer arguments are passed in than the function believes, or the types of arguments are incorrect, this could cause it to read into invalid areas of memory and can lead to vulnerabilities like the format string attack.

The invokation of above function is straightforward:

double c =average(5,31.1,24.5,67.12,13.75,91.3);

Here we have supplied the no. of variable arguments in the function call as the first argument (fixed =5).

Thereafter we initialise va_start to point to the start of the va_list which here consists of (31.1,24.5,67.12,13.75,91.3)

Then to access each variable argument of the va_list starting from va_start, we use va_arg which accesses and typecasts each argument to the dataype specified (double in our case).

Share this post



Add comment

Please refrain from using slang or abusive language in the comments.
To avoid waiting for your comment to be published after being reviewed, please log in as a registered user.


Security code
Refresh

Web Hosting