Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing variable number of arguments of different types in c [duplicate]

Tags:

c

I want to make an function which will take variable number of arguments of different types. My problem is how can i parse the argument types. Like caller can pass arguments of any type in any order (without specifying format specifier). So at the calling function how can i differentiate between types.

How to print all values passed by the caller in the function var_argument ?

Let say I want to do sprintf inside var_argument function of the parameters passed by the caller

Here is my C code

#include <stdio.h>
#include <stdarg.h>
void var_argument(int num,...);

int main()
{
 var_argument(3,"Hello",7.87f,6);
 var_argument(3,7.87f,"Hello",6);
 return 0;
}

void var_argument(int num,...)
{
 char str[80];
/* What code should I write to differentiate between types and to print all the values passed by the caller */     

 va_list list;
 va_start(list,num);

 /* How to do sprintf of the parameter passed to this function and store 
 the formatted output in the array str  */
}
like image 844
vivek Avatar asked Oct 03 '17 14:10

vivek


1 Answers

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);
}
like image 153
Iharob Al Asimi Avatar answered Oct 11 '22 02:10

Iharob Al Asimi