0

I'm trying to achieve something like this: I have

struct {
   int var1;
   int var2;
   int var3;
   ......
   int var31;
}

now I have some integer 'r' that I read on runtime, and I want to print value of var##r (that is, if r=6, print var6 from structure), is it possible via preprocessor directives? I understand I can do this by jumping from var1's address sizeof(int) * r times but I want preprocessor to generate whole if-else chain, can I make it somehow do this?

UPDATE: Forgot to mention, cannot modify given struct, thus cannot use array

UPDATE2: I have those limitations (no arrays, nu jumps) because at the end I'm parsing syntax tree generated by clang and I want to have pure if/else statements there

Zhani Baramidze
  • 1,407
  • 1
  • 13
  • 32

1 Answers1

0

If course you could generate the if-else chain using the preprocessor if you really want to (you probably don't), but if it's only this occurence it's most probably not worth it. I think you should really reconsider the possibility to use an array or offsets into the struct.

You could to some limited extent construct loops in the preprocessor. The limitation is that you can't write proper loops so you will end up in a construct that will end up with a limited amount of iterations. Basically what you do to loop n times is to expand LOOP(n,...) to LOOP#n(...) and then define LOOPn# for all possible values ofn`.

So what we would want is something like:

 if( 0 )                 ; // Note: empty statement
 else if( r == 1 )       return o->var1;
 else if( r == 2 )       return o->var2;
 // etc

The if(0) is to make each variable be handled textually the same. So we can do the first step to define that:

 #define HANDLE_VAR(n) else if( r == n ) return o->var ## n;

this would mean that we write it

 if(0) ;
 HANDLE_VAR(1)
 HANDLE_VAR(2)
 //  etc

Then we define our loop construct:

 #define LOOP(n,M) LOOP ## n(M)
 #define LOOP(1) M(1)
 #define LOOP(2) M(1) M(2)
 // etc

then our construct would be

 if( 0 ) ; LOOP(31,HANDLE_VAR)

And finally we would wrap it all into a macro:

 #define RETURN_VAR if(0) ; LOOP(31,HANDLE_VAR)

There are other options however. The most normal solution would be to use an array to store the variables.

Another would be to write your own preprocessor that supports proper looping, there are ready template processors (genshi for example) that support that.

A third is to calculate the offset into the struct. The suggested method of doing this is not standard compliant though. What you need to do is to have an array of offsets stored:

int StructName::* var_off[] = {
    NULL,
    &StructName::var1,
    &StructName::var2,
    // etc
};

and then use o.*var_off[r] to access var##r (after checking that r is in range of course).

skyking
  • 13,817
  • 1
  • 35
  • 57
  • `offsetof` is only good for standard layout types. There should be a static assert there to verify `StructName` is standard layout. – StoryTeller - Unslander Monica Jul 17 '17 at 06:27
  • @StoryTeller I was thinking C, in C++ I don't think offsetof is approprate for this situation - I've modified the answer to use pointer to members instead (I think they should work regardless of standard layout). – skyking Jul 17 '17 at 06:55