Simulater/Generated switch statement range in c

2020-05-07 07:03发布

问题:

Is there a hack to support range case in a c(99?) or objective C switch statement ? I know this is not supported to write something like this:

switch(x)
   case 1:
   case 2..10:
   case 11:

But I was thinking there should be a way to generate code with a #define macro. Of course I can define a macro with the list of cases but I was hoping for a more elegant way like CASERANGE(x,x+10) which would generate:

case x
case x+1
case x+2

is it even possible ?

回答1:

GCC has an extension to the C language that allows something similar to your first example, but other than that, if there was a portable/ANSI way of doing it, it would have been done by now. I don't believe there is one.



回答2:

Doing this with macros is near to or impossible. Compiler extensions exist, but they are compiler specific and not cross-platform/standard. There is no standard way to do this, use if/else chains instead.



回答3:

In modern C (C99, with variable length macros), doing this with macros is possible. But you probably wouldn't want to code this completely yourself. P99 provides a toolbox for this. In particular there is a meta-macro P99_FOR that allows you to do unrolling of finite length argument lists.

#define P00_CASE_FL(NAME, X, I) case I: NAME(X); break
#define CASES_FL(NAME, ...) P99_FOR(NAME, P99_NARG(__VA_ARGS__), P00_SEQ, P00_CASE_FL, __VA_ARGS__)

would expand CASES_FL(myFunc, oi, ui, ei) to something like

case 0: myFunc(oi); break; case 1: myFunc(ui); break; case 2: myFunc(ei); break

Edit: to reply to the concrete question

#define P00_CASESEP(NAME, I, X, Y) X:; Y
#define P00_CASERANGE(NAME, X, I) case ((NAME)+I)
#define P99_CASERANGE(START, LEN) P99_FOR(START, LEN, P00_CASESEP, P00_CASERANGE, P99_REP(LEN,))

where P00_CASESEP just ensures that there are the :; between the cases, and P99_REP generates a list with LEN empty arguments.

You'd use that e.g as

switch(i) {
P99_CASERANGE('0',10): return i;
}

Observe the : after the macro to keep it as close as possible to the usual case syntax, and also that the LEN parameter has to expand to a plain decimal number, not an expression or so.