Home > Blockchain >  Get the value of a macro using a string with macro name
Get the value of a macro using a string with macro name

Time:01-26

I have a set of macro definitions that the name only change on the number between "C_" and "_E". What I need is a macro that gets a integer variable and returns the integer value of the corresponding macro definition in case it exists, if it does not exist, it returns "-1" or gives a compile error. Is that possible? The code I need is something like this:

#include <stdio.h>

#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420

#define MACRO_VAL(x) ... // return the value of the macro C_x_E when x=1,2,3 or 4

void main() {
  uint8_t n;
  for(n=1;n<=4;n  ) printf("val %u: %u\n",n, MACRO_VAL(n));
}

Expected output:

val 1: 4
val 2: 2
val 3: 0
val 4: 420

According to my search, this is not possible, but I can swear I did cross this solution once, but I didn't need it back then although I thought it could be helpful.

CodePudding user response:

If you need to have a macro specifically, not a function, then it must be that a macro that expands to a function call is not acceptable either. That makes sense to me only if you need the conversion of macro number to macro expansion to be performed at compile time, by the preprocessor. That doesn't appear to be a necessity for the example code, but there are cases where it would indeed be needed.

And that's too bad, because the C preprocessor then provides no way to achieve what you ask. Variables do not exist or have values at compile time, so there is no way at compile time for the compiler to convert a variable name to the value it represents, much less to build a macro name out of it, much less to expand such a name to its replacement text.

You could, however, do it with numeric literals instead of a variable:

#define EXPAND(x) x
#define MACRO_VAL(n) EXPAND(C_ ## n ## _E)

printf("val %d: %d\n",n, 1, MACRO_VAL(1));
printf("val %d: %d\n",n, 2, MACRO_VAL(2));
printf("val %d: %d\n",n, 3, MACRO_VAL(3));
printf("val %d: %d\n",n, 4, MACRO_VAL(4));

If you try to expand that with an argument that does not produce the name of a defined macro or in-scope variable then that (almost surely) will produce a compile-time error for a reference to an undefined variable.


If run-time evaluation were acceptable after all, then you could write a function that does it (which you could wrap in a macro if you wanted):

#define MACRO_VAL(n) lookup_macro(int n)

#define EXPAND(x) x
#define MACRO_CASE(i) case i: return EXPAND(C_ ## i ## _E)
int lookup_macro(int n) {
    switch (n) {
       MACRO_CASE(1);
       MACRO_CASE(2);
       MACRO_CASE(3);
       MACRO_CASE(4);
       default: return -1;
    }
}

That will return -1 for an arithmetic argument that is not covered by the defined cases.

You could also consider a lookup table, possibly wrapped in a function, but that would require somewhat more code to provide a -1 result in the event of an argument that doesn't match any macro, especially if the macro numbers are not all consecutive or if the least of them is not known in advance.

CodePudding user response:

Token pasting approaches are inappropriate as x is a variable name.

Here is a simplistic approach that will work as long as the macro argument is an expression without side effects:

#include <stdio.h>

#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420

// return the value of the macro C_x_E when x=1,2,3 or 4
#define MACRO_VAL(x)  ((x) == 1 ? C_1_E : \
                       (x) == 2 ? C_2_E : \
                       (x) == 3 ? C_3_E : \
                       (x) == 4 ? C_4_E : -1)

int main() {
    int n;
    for (n = 1; n <= 4; n  )
        printf("val %u: %u\n", n, MACRO_VAL(n));
    return 0;
}
  •  Tags:  
  • Related