Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
111 views
in Technique[技术] by (71.8m points)

Handling double-variable switch statement with macro in C

Let's say I have two pointers to two structs a and b. These two structs each contain an enum, which we'll call x. Given any possible a and b, I want to call a specific function based on the values of their x enums. What is interesting in my case is that the functions that I want to call look like:

X0_to_X1();
X0_to_X2();
...
X1_to_X0();
...
etc

where X0, X1 etc are possible values of the enum x, meaning that there are X_to_Y functions for every and each combination of the values of the x enum.

The obvious "naive" solution to this would be a switch statement which would be quite big (given that x has quite a few possible values):

switch (a->x) {
    case X0:
        switch (b->x) {
            case X1:
                X0_to_X1();
                break;

// ... and so on and so forth for every possible pair!

My first attempt at solving this a bit more elegantly was to implement a macro that, given two values of x, could form a function call:

#define CALL_FUNCTION(x1, x2) x1 ## _to_ ## x2 ()

This however does not work, as in my code I never can know the actual values of x before runtime, so it ends up looking like:

CALL_FUNCTION(a->x, b->x);

which of course gets converted to:

a->x_to_b->x();

which makes absolutely no sense.

Is there a way to solve this problem more elegantly, or should I just bite the bullet and implement the enormous switch statement instead?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This problem screams for a lookup table, where you store pointers to the various functions and they are keyed by the enumeration values.

If your enum values are sequential (and no two enumeration constants share the same value), then you can build a lookup table as a simple 2D array:

enum x_t { X0, X1, X2, ..., NUM_X }; 
void (*lookup[NUM_X][NUM_X])(void) = {
  { NULL, X0_to_X1, X0_to_X2, X0_to_X3, ... },
  { X1_to_X0, NULL, X1_to_X2, X1_to_X3, ... },
  { X2_to_X0, X2_to_X1, NULL, X2_to_X3, ... },
  ...
};

That assumes you don’t have an "identity” function when your x and y are the same.

Then, you call the desired function by indexing into to table like so:

if ( x != y )
  lookup[x][y]();

No, it isn’t pretty, but it beats nested switch statements. You can hide that behind a macro or another function call if you wish.

If your enumeration values aren’t sequential then this particular implementation won’t work - you’d have to build your lookup table a different way, using lists or sparse matrices. But while the setup code may be tedious, it will greatly simplify the logic on the calling side.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...