2020-08-27

Pseudo C++ using cpp (the RevK macro)

I am not sure if this is evil, or genius, or both. Either way I take full credit.

Mainly for a library where we want to add extra optional options in the future, so want almost C++ style optional and tagged arguments to a function, but in normal C (because C++ is just evil all by itself).


Not quite as flexible as C++, as no defaults for missing arguments, but you can often live with that knowing they are zero or NULL.

Unless someone can cite a prior art - please call this the RevK macro.

P.S. I have updated my string decimal library to use this, and it is way neater!

Some explanation...

Normally a function call in C has a fixed set of arguments. Well, not quite, some can have variable arguments at the end, like printf(...) but that is handled in a special way and you have to know (usually from a format string) how many arguments and which type.

However, in some languages, like C++, you can have optional arguments which are pre-defined types and names, but you can stop early in the list. In C++ you can say what default these missing arguments have. You also have the option to leave some arguments our and "tag" some others.

So, the idea you can call myfunc("hello",flag2:1) is setting the first argument (s), and the third (flag2) and not specifying the middle one (flag1) which ends up zeroed. I can't set defaults but can expect unspecified to be zeroed.

Now, normally, if I had some function you call as func(a,b,c) and I want some extra option later on, I would have to either change to func(a,b,c,d) everywhere it is used in every program, even if people specify d as 0 or NULL,  or make a new separate function that takes the extra argument as an alternative, e.g. func2(a,b,c,d).

With this trick I am able to add this extra argument which is optional, knowing that if the extra argument is not specified it has a known value of 0/NULL.

The way the trick works is by using the standard C pre-processor which does text substitution, and expanding the full list of arguments (...) in the macro (as __VA_ARGS__) within a structure initialisation. Unlike function arguments, C has a syntax to initialise a structure which allows you to omit arguments and tag arguments. I am using that syntax in the function, so myfunc("hello",flag2:1) becomes a structure initialiser {"hello",flag2:1} and this structure is passed to the function.

Of course I could just used C++, but that comes with a lot of other baggage, and not something I am that keen on. It has its merits and works well for some applications.

8 comments:

  1. Nice!

    Side note: slightly nonportable: the no-argument variant (the first call to myfunc()) is not valid C99 nor C11, but *is* a GCC extension widely supported by other compilers. The portable (but ever so ugly and weird) call there is myfunc("hello",);

    ReplyDelete
    Replies
    1. Surely a structure initialised as {} is valid even in C99? and hence the () version would work after cpp expansion. TBH I use too many gcc extras already that it is not an issue, but interesting.

      Delete
    2. ... oh yeah, it's inside an initializer, so yes, that would work, and also I shouldn't post when exhausted (i.e., at all, right now).

      Delete
  2. For the non-C programmers like me, would you mind explaining step by step what's going on here and why it's worthy of being RevKified?

    ReplyDelete
  3. AFAIK, that colon syntax is a non-standard (and obsolete) GCC extension.

    The standardised form being ".fieldname".

    I'd not be surprised if the colon form is removed in some future version of GCC.

    https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Designated-Inits.html

    Yes, others have used a macro around such struct initialisers, but in the standard form.

    ReplyDelete
    Replies
    1. Interesting. The main trick is using it in a macro to make it seem like function arguments, and the .x= syntax is not quite as nice for that but sill works as a way to make variable argument and tagged functions in C.

      Delete
  4. If you are challenging C to this level and need the kind of power that C++ has bu i thought its ugliness and madness, then definitely take a look at D - google "DLang". (I’ve mentioned this before, so apologies.) D has compile-time function evaluation and a ultra-powerful templates with a sane syntax. See: https://dlang.org/ and http://ddili.org/ders/d.en/

    ReplyDelete

Comments are moderated purely to filter out obvious spam, but it means they may not show immediately.