Cstdarg
lastmod 2023-04-04created 2019-03-047 edits
Variadic arguments in C.
Implementation
-
va_list - A pointer that will point to the start address of each variadic argument. It looks fancy, but internally it is defined as
char *.
-
va_start - An important macro that tells the pointer created with
va_listthe address of the first of the variadic arguments. It actually looks like this. (Based on Microsoft Visual Studio)
:
:* ap: Holds the pointer created with va_list.
:* v: Holds the last fixed argument.
:* _ADDRESSOF(v) => &(v), a macro that converts it into an address.
:* _INTSIZEOF(n) => ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ), a macro that gets the size of the last fixed argument and computes the in-memory distance to the start address of the next argument, i.e. the start address of the variadic arguments.
-
va_arg - A macro that moves the
va_listpointer, which points to a particular variadic argument, to the next variadic argument. It looks like this.
:
:* ap: Holds the pointer created with va_list.
:* t: Holds a type name such as int, long, or double.
- Note that for
charandshortyou reportedly have to useintinstead, and forflaotuse double instead, and then cast the type. (e.g.char ch = (char) va_arg(ap, int);)
-
va_end - Used when you are done with the variadic argument variable. Looking at its form, it's simply a macro that sets the pointer back to NULL, but since you never know what might happen in a program, make sure not to skip it.
:
:* ap: Holds the pointer created with va_list.
Example
#include<stdarg.h>
#include<stdio.h>
int sum(int, ...);
int main(void) {
printf("Sum of 10, 20 and 30 = %d\n", sum(3, 10, 20, 30) );
printf("Sum of 4, 20, 25 and 30 = %d\n", sum(4, 4, 20, 25, 30) );
return 0;
}
int sum(int num_args, ...) {
int val = 0;
va_list ap;
int i;
va_start(ap, num_args);
for(i = 0; i < num_args; i++) {
val += va_arg(ap, int);
}
va_end(ap);
return val;
}
Printf example
#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
How to pass a va_list
void _printf(const char * format, ...)
{
char buffer[2048] = {0,};
va_list args;
va_start(args, format);
vsnprintf(buffer, 2048, format, args);
va_end(args);
_print(buffer);
}
See also
Favorite site
- [Recommended] Let's use variadic arguments (variadic parameters) in C 1
References
-
Norux.me_-_How_to_use_the_va_list.pdf ↩