Monday Jan 11, 2010

Ever wanted to be able to write C function calls with arguments named in the call?

Have you ever wished you could write

        result = foo(.arg3 = xyz, .arg2 = abc);
as you can in some programming languages? If not then you've probably not met an API with functions that have a dozen arguments most of which take default values. There exist such APIs, and despite any revulsion you might feel about them, there's often good reasons for the need for so many parameters that can be defaulted.

Well, you can get pretty close to such syntax, actually. I don't know why, but I thought of the following hack at 1AM last Thursday, trying to sleep:

struct foo_args {
        type1 arg1;
        type2 arg2;
        type3 arg3;
};
#define CALL_W_NAMED_ARGS3(result, fname, ...) \\
        do { \\
                struct fname ## _args _a = { __VA_ARGS__ };
                (result) = fname(_a.arg1, _a.arg2, _a.arg3);
        } while (0)
...
        CALL_W_NAMED_ARGS3(res, foo, .arg2 = xyz, .arg3 = abc);

This relies on C99 struct initializer syntax and variadic macros, but it works. Arguments with non-zero default values can still be initialized since C99 struct initializer syntax allows fields to be assigned more than once.

If you use GCC's statement expressions extension (which, incidentally, is supported by Sun Studio), you can even do this:

#define CALL_W_NAMED_ARGS3(fname, ...) \\
        ({ \\
                struct fname ## _args _a = { __VA_ARGS__ };
                fname(_a.arg1, _a.arg2, _a.arg3);
        })
...
        res = CALL_W_NAMED_ARGS3(foo, .arg2 = xyz, .arg3 = abc);

You can even define a macro that allows you to call functions by pointer, provided you have suitable typedefs:

struct foo_t_args {
...
};
#define CALL_PTR_W_NAMED_ARGS3(ftype, func, ...) \\
        ({ \\
                struct ftype ## _args _a = { __VA_ARGS__ };
                func(_a.arg1, _a.arg2, _a.arg3);
        })
...
        foo_t f = ...;
        res = CALL_W_NAMED_ARGS3(foo_t, f, .arg2 = xyz, .arg3 = abc);

Useful? I'm not sure that I'd use it. I did a brief search and couldn't find anything on this bit of black magic, so I thought I should at least blog it.

What's interesting though is that C99 introduced initializer syntax that allows out of order, named field references (with missing fields getting initialized to zero) for structs (and arrays) but not function calls. The reason surely must be that while structs may not have unnamed fields, function prototypes not only may, but generally do have unnamed fields. (That and maybe no one thought of function calls with arguments named in the call parameter list).

About

I'm an engineer at Oracle (erstwhile Sun), where I've been since 2002, working on Sun_SSH, Solaris Kerberos, Active Directory interoperability, Lustre, and misc. other things.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today