This is somehow already done, for example printf()
has such mechanism. For variable arguments functions, you need a first parameter that is not part of the variable parameters, use it as a format string to determine the type of parameter x at position n.
Because the first parameter is mandatory, so you MUST have such a parameter and it seems natural to use it as an indicator of what to expect in the variable arguments.
Take this as an example,
#include <stdio.h>
#include <stdarg.h>
int
variable(const char *format, ...)
{
va_list args;
int count;
va_start(args, format);
count = 0;
while (*format != '\0') {
switch (*format++) {
case 's':
fprintf(stdout, "arg[%d]: %s\n", count, va_arg(args, const char *));
break;
case 'd':
fprintf(stdout, "arg[%d]: %d\n", count, va_arg(args, int));
break;
case 'f':
fprintf(stdout, "arg[%d]: %f\n", count, va_arg(args, double));
break;
}
count += 1;
}
va_end(args);
return 0;
}
int
main(void)
{
variable("sdf", "Example", 3, 3.1416);
}
Of course, any mismatch between the specifiers and the actual types of the arguments will lead to undefined behavior and as a logical consequence to undesired behavior. So you must be very careful or, use printf()
style specifiers and tell the compiler to warn if such mismatch occurs.
Another solution, is to do it like some of glib's functions, pass a type specifier and immediately after the parameter, with a last value that would indicate the end of the parameters. Parameter "specifiers" could be an enum
enumerating all supported types, like this
#include <stdio.h>
#include <stdarg.h>
enum types {
String, Integer, Double, Float = Double, /* unless you want to store the value in a poitner
* there is normally no difference between these
*/
End
};
int
variable(enum types type, ...)
{
va_list args;
int count;
va_start(args, type);
count = 0;
while (type != End) {
switch (type) {
case String:
fprintf(stdout, "arg[%d]: %s\n", count, va_arg(args, const char *));
break;
case Integer:
fprintf(stdout, "arg[%d]: %d\n", count, va_arg(args, int));
break;
case Double:
fprintf(stdout, "arg[%d]: %f\n", count, va_arg(args, double));
break;
default:
fprintf(stderr, "unknown type specifier\n");
break;
}
type = va_arg(args, enum types);
count += 1;
}
va_end(args);
return 0;
}
int
main(void)
{
variable(String, "Example", Integer, 3, Double, 3.1416, End);
}