In the C language, by implementing the function as a variable parameter form, the function can be made to accept more than one arbitrary number of parameters (not fixed).
Let's look at an example and dissect it to understand variadic parameter lists
Compiler: vs2013
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
int average(int n, ...)
{
va_list arg;
int i = 0;
int sum = 0;
va_start(arg, n);
for (i = 0; i < n; i++)
{
sum += va_arg(arg, int);
}
va_end(arg);
return sum / n;
}
int main()
{
int avg = average(4, 1, 2, 3, 5);
printf("%d\n", avg);
system("pause");
return 0;
}
First, let's analyze part of the code
1.
int average(int n, ...) // ... 未知参数列表,n为未知参数列表个数
//将部分参数(1, 2, 3, 5)传给了未知参数列表
2.
code
va_list arg;
go to definition
typedef char * va_list;
3.
code
va_start(arg, n);
go to definition
#define va_start _crt_va_start
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _ADDRESSOF(v) ( &(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
4.
code
va_arg(arg, int);
go to definition
#define va_arg _crt_va_arg
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
5.
code
va_end(arg);
go to definition
#define va_end _crt_va_end
//宏,_crt_va_end被重命名为 va_end
#define _crt_va_end(ap) ( ap = (va_list)0 )
//宏,( ap = (va_list)0 )
After that, we replace part of the code of the average function
int average(int n, ...)
{
char *arg;
int i = 0;
int sum = 0;
arg = (char *)(&(n)) + 4;
for (i = 0; i < n; i++)
{
sum += *(int *)((arg += 4) - 4);
}
arg = (char *)0;
return sum / n;
}
From the above, we can see that
- Declare a variable of type va_list for accessing the undetermined part of the argument list.
- This variable is initialized with va_start, whose first parameter is the variable name of va_list, and the second parameter is the last named parameter before the ellipsis. The initialization procedure sets the arg variable to point to the first argument of the variable argument section.
- In order to access the arguments, va_arg is used. This macro accepts two arguments: the va_list variable and the type of the next argument in the argument list. In the above example, all variadic parameters are integers. va_arg returns the value of this parameter and makes va_arg point to the next variable parameter.
- Finally, after we have accessed the last parameter, we need to call va_end.
Applications of variable parameter lists
1. Use variable parameters, implement functions, and find the maximum value of function parameters
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
int Max(int n, ...)
{
va_list arg;
int i;
int max = 0;
va_start(arg, n);
max = va_arg(arg, int);
for (i = 1; i < n; i++)
{
int tmp = va_arg(arg, int);
if (max < tmp)
max = tmp;
}
va_end(arg);
return max;
}
int main()
{
int ret = Max(4, 1, 2, 3, 4);
printf("%d\n", ret);
system("pause");
return 0;
}
Simulate a simple printf function
To simulate a simple printf function, you need to use the first parameter passed in to traverse the string. If you encounter characters such as d, c, s, etc. (simulate %d, %c, %s), use va_age obtains and outputs the parameters in the corresponding unknown parameter list. If it is not encountered, it will be output as it is.
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <windows.h>
void print(const char *format, ...)
{
char *str = (char *)format;
va_list arg;
va_start(arg, format);
while (*str != '\0')
{
int ch;
char *s;
switch (*str)
{
case 'd':
ch = va_arg(arg, int);
while (ch > 10)
{
int d = 0;
int i = 1;
d = ch / 10;
while (d > 10)
{
d = d / 10;
i++;
}
d = d + 48;
putchar(d);
i = (int)pow(10, i);
ch = ch % i;
}
ch = ch + 48;
putchar(ch);
str++;
break;
case 'c':
putchar(va_arg(arg, char));
str++;
break;
case 's':
s = va_arg(arg, char*);
while (*s != '\0')
{
putchar(*s);
s++;
}
str++;
break;
default:
putchar(*str);
str++;
break;
}
}
}
int main()
{
print("s ccc d.\n", "hello", 'b', 'i', 't', 1234);
system("pause");
return 0;
}