In modern C (C99, with variable-length macros), this can be accomplished using macros. But you probably would not want to code this completely. P99 provides a set of tools for this. In particular, there is a P99_FOR meta macro that allows you to expand lists of arguments of finite length.
#define P00_CASE_FL(NAME, X, I) case I: NAME(X); break
will extend 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: answer a specific 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 between cases there is P00_CASESEP , and P99_REP generates a list with LEN empty arguments.
Would you use this, for example, as
switch(i) { P99_CASERANGE('0',10): return i; }
Observe : after the macro, that it is as close as possible to the usual case syntax, and also that the LEN parameter should expand to a simple decimal number, not an expression or so.