3. <stdarg.h> Variable Argument Lists
If a parameter list ends with an ellipsis "..." in a function, then the function may accept more arguments than the number of parameters explicitly described, which are called unnamed arguments.
The header <stdarg.h> provides facilities for stepping through a variable argument list or a list of unnamed function arguments.
Suppose lastarg is the last named parameter of a function f with a variable number of arguments. Then declare within f a variable of type va_list that will point to each argument in turn:
va_list ap;
ap must be initialized once with the macro va_start before any unnamed argument is accessed:
va_start(va_list ap, lastarg);
Thereafter, each execution of the macro va_arg will produce a value that has the type and value of the next unnamed argument, and will also modify ap so the next use of va_arg returns the next argument:
type va_arg(va_list ap, type);
The macro
void va_end(va_list ap);
must be called once after the arguments have been processed but before f is exited.
When unnamed arguments are passed, default argument promotion is applied to each argument as follows: integral promotion is performed on each argument of integral type, and each float argument is converted to double.
A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type may be used in an expression wherever an integer may be used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion.
EXAMPLE CODES
1. stdarg.h
l sum-1.c
#include <stdio.h>
#include <stdarg.h>
int sum(int n, ...) { // sum of n int values -- variadic function
int i, res = 0;
va_list ap; // pointer to unnamed arg
va_start(ap, n); // make ap point to 1st unnamed arg
for (i = 0; i < n; i++)
res += va_arg(ap, int);
va_end(ap); // clean up
return res;
}
void main() {
printf("%d %d\n", sum(2, 1, 2), sum(3, 10, 20, 30, 40));
}
> sum-1
3 60
l sum-2.c
#include <stdio.h>
#include <stdarg.h>
int vsum(int n, va_list arg) { // sum of n int values
int i, res = 0;
for (i = 0; i < n; i++)
res += va_arg(arg, int);
return res;
}
int sum(int n, ...) { // sum of n int values
int res;
va_list arg;
va_start(arg, n);
res = vsum(n, arg);
va_end(arg);
return res;
}
void main() {
printf("%d %d\n", sum(2, 1, 2), sum(3, 10, 20, 30, 40));
}
> sum-2
3 60
l print.c
#include <stdio.h>
#include <stdarg.h>
// conversion specifications: %c, %d %f %s %%
void print(const char *format, ...) {
const char *p;
va_list ap;
va_start(ap, format);
for (p = format; *p; p++) {
if (*p != '%') { putchar(*p); continue; }
switch (*++p) {
case 'd': printf("%d", va_arg(ap, int)); break;
case 'f': printf("%f", va_arg(ap, double)); break;
case 's': fputs(va_arg(ap, char *), stdout); break;
case 'c': putchar(va_arg(ap, int)); break;
default: putchar(*p); break;
}
}
va_end(ap);
}
void main() {
print("100%% %c %d %d %d %f %f %s\n",
'A', 'A', (short)10, 10, 3.4, 3.4f, "SKHU CC");
}
> print
100% A 65 10 10 3.400000 3.400000 SKHU CC
l trace.c
#include <stdio.h>
#include <stdarg.h>
#ifdef WIN32 // VC
#define __func__ __FUNCTION__ // function name
#endif
// variadic macro
#ifdef _DEBUG // VC debug configuration
#define TRACE(...) trace(__FILE__, __func__, __LINE__, __VA_ARGS__)
#else
#define TRACE(...)
#endif
void trace(const char *file, const char *func, int line, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
printf("[%s:%s:%d] ", file, func, line);
vprintf(fmt, ap);
va_end(ap);
}
int sum(int a, int b) {
int res;
TRACE("a = %d, b = %d\n", a, b);
res = a + b;
TRACE("res = %d\n", res);
return res;
}
void main() {
printf("sum(1, 2) = %d\n", sum(1, 2));
}
> cl trace.c && trace
$ gcc trace.c -o trace; ./trace
sum(1, 2) = 3
> cl /D_DEBUG -DWIN32 trace.c && trace
$ gcc -D_DEBUG trace.c -o trace; ./trace
[trace.c:sum:21] a = 1, b = 2
[trace.c:sum:23] res = 3
sum(1, 2) = 3
n VC IDE: Debug 및 Release Configuration에서 각각 Build 후 실행