simont: A picture of me in 2016 (Default)
simont ([personal profile] simont) wrote2012-02-21 11:53 am

C abuse of the week

I continue to be amazed at the number of bizarre things you can arrange to do using the C preprocessor, the switch statement, and a strong stomach. I've previously used the combination to implement coroutines, of course, and also a modified version of for which performs its test after the loop body rather than before it.

Chris mentioned to me this morning the fact that you could write this sort of thing:

    switch (get_value()) case 1: case 2: case 3: do_stuff();

which has the handy effect of calling get_value() only once and then testing its return value against several possibilities (though they're constrained to be compile-time constant integers). But of course it's hopelessly ugly, so he challenged me to wrap it up in a macro or two. (Not that that stops it being ugly, exactly. But differently ugly. :-)

The obvious solution seemed to me to be this:

#define IF_IN_LIST(expr,list) switch (expr) case list:
#define OR : case

which then lets you write compound statements that only look slightly un-C-ish:

    IF_IN_LIST(get_value(), 1 OR 2 OR 3)
do_stuff();

But then I realised that if you dangle a few more oddities off the switch statement, you can do better. If you do it like this:

#define IF_IN_LIST(expr,list) switch (expr) default: if (0) case list:
#define OR : case

then your uses of the macro can now include an optional else clause!

    IF_IN_LIST(get_value(), 1 OR 2 OR 3)
do_stuff();
else
do_other_stuff();

(And naturally both versions work with either bare statements or braced blocks.)

[identity profile] ptc24.livejournal.com 2012-02-22 03:42 pm (UTC)(link)
That's... quite special.

Your use of if(0) is rather better than the tawdry use I sometimes make of the Java equivalent, if(false) - the Java compiler complains of unreachable code, and sometimes when you're working on something, it's nice to suppress that with an if(false) return;. Of course, Java is boring and won't let you jump into blocks with a case: like that...

[identity profile] ptc24.livejournal.com 2012-02-22 03:50 pm (UTC)(link)
The general case: it doesn't matter whether the code is reachable or not, you can't put case statements in sub-blocks. Not even sub-blocks that are just sub-blocks on their own (i.e. no if or for or while or whatever in front of them, they just start with {).

[identity profile] xraycb.livejournal.com 2012-02-25 12:30 pm (UTC)(link)
I like this, almost enough that I might be tempted to use it in production code...