Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic functions and arguments assignment in C/C++

I was wondering if in C/C++ language it is possible to pass arguments to function in key-value form. For example in python you can do:

def some_function(arg0 = "default_value", arg1):
    # (...)

value1 = "passed_value"
some_function(arg1 = value1)

So the alternative code in C could look like this:

void some_function(char *arg0 = "default_value", char *arg1)
{
    ;
}

int main()
{
    char *value1 = "passed_value";
    some_function(arg1 = value1);
    return(0);
}

So the arguments to use in some_function would be:

arg0 = "default_value"

arg1 = "passed_value"

Any ideas?

like image 836
Rizo Avatar asked May 13 '10 10:05

Rizo


3 Answers

Here's a C99 solution using compound literals and variadic macros:

#include <stdio.h>

#define some_func(...) some_func_((struct some_func_args_){ __VA_ARGS__ })

struct some_func_args_
{
    const char *arg1;
    const char *arg2;
};

static void some_func_(struct some_func_args_ args)
{
    if(!args.arg1) args.arg1 = "default";
    printf("---\narg1 = %s\narg2 = %s\n", args.arg1, args.arg2);
}

int main(void)
{
    some_func("foo", "bar");
    some_func(.arg1 = "spam");
    some_func(.arg2 = "eggs");
    return 0;
}
like image 188
Christoph Avatar answered Oct 03 '22 11:10

Christoph


You can emulate this in C++ with this:

struct params {
   string foo_;
   double bar_;
   short  xxx_;
   params() : foo_("123"), bar_(3.1415), xxx_(42) {} // default parameters
   params& foo(string s) {foo_=s;return *this;}
   params& bar(double x) {bar_=x;return *this;}
   params& xxx(short x) {xxx_=x;return *this;}
};

void some_function(params const & p);

int main() {
   some_function(params().bar(99.9).xxx(23));
}

But IMHO it's not worth the effort. Too much boiler plate.

If I remember correctly Stroustrup's book "Design and Evolution of C++" contains a section that discusses this feature request of "named arguments". The conclusion was something along the lines of: not a good idea. Check it out if you want details.

like image 23
sellibitze Avatar answered Oct 03 '22 12:10

sellibitze


Named arguments are not supported in C, but you could emulate named parameters it using variadic function (though you loose type safety):

#include <stdarg.h>

void do_sth (int foo, ...)
{
    int baz = 7;             /* "baz" argument */
    const char *xyz = "xyz"; /* "xyz" argument */

    /* Parse named parameters */
    va_list ap;
    va_start (ap, foo);
    for (;;) {
        const char *key = va_arg (ap, char *);
        if (key == NULL) {
            /* Terminator */
            break;
        } else if (strcmp (key, "baz") == 0) {
            baz = va_arg (ap, int);
        } else if (strcmp (key, "xyz") == 0) {
            xyz = va_arg (ap, char *);
        } else {
            /* Handle error */
        }
    }
    va_end (ap);

    /* do something useful */
}

do_sth (1, NULL);                             // no named parameters
do_sth (2, "baz", 12, NULL);                  // baz = 12
do_sth (3, "xyz", "foobaz", NULL);            // xyz = "foobaz"
do_sth (4, "baz", 12, "xyz", "foobaz", NULL); // baz = 12, xyz = "foobaz"

Just remember to end optional arguments list with NULL. You could also use some ENUM as keys instead of character strings.

This technique is used, for exapmle, in GTK+:

  • gtk_list_store_set
  • gtk_message_dialog_new
like image 35
el.pescado - нет войне Avatar answered Oct 03 '22 13:10

el.pescado - нет войне