Home > Mobile >  How to change a constant expression to a literal number during preprocessing? (use gcc)
How to change a constant expression to a literal number during preprocessing? (use gcc)

Time:12-22

The code like:

void f1(){
    /* ... */
}

void f2(){
    /* ... */
}

int main()
{
    const int n=2;
    USE(f, n)();
    return 0;
}

I hope it can call f2().

if we just define like:

#define PASTE(a,b) a##b
#define USE(a,b) PASTE(a,b)

it will call fn(). So we should define a new macro to change n to 2, like:

#define PASTE(a,b) a##b
#define CHANGE_constexpr_TO_literal(n)  // I don't know how to define
#define USE(a,b) PASTE(a,CHANGE_constexpr_TO_literal(b))

then the expansion of CHANGE_constexpr_TO_literal(n) will be 2 .

Is it possible to define the macro to force a constexpr n to be literal n? How to define it if possible?

Note:

  • I use GCC compiler, so gnu c extensions are available.
  • Only during preprocessing. I know how to do while during compilation. But it doesn't have to be a macro.
  • Furthermore, is it possible to change a string constant expression to a literal string? And how to do it?

CodePudding user response:

It cannot be done. Preprocessor operates only on tokens before any C grammar rules are applied. Therefore const int n is not even parsed when USE macro is about to be expanded.

The workaround would be defining USE() as a chain of conditional operator selecting an desired function pointer depending on n.

#define USE(f, n) (    \
   (n == 0) ? f ## 0 : \
   (n == 1) ? f ## 1 : \
   (n == 2) ? f ## 2 : \
   NULL)

The advantage of this approach is that if n is a constant expression then the value of USE() is a constant expression as well.

BTW. In standard C the const int n = 2; does not make n a constant expression. Use either a macro or enum:

#define n 2

or

enum { n = 2 };

CodePudding user response:

The main reason why we still use #define constants and not type safe const variables is that the former can be used in pre-processor macros. A variable in C is never a compile-time constant and its value can't be accessed by the pre-processor.

So the fix is to change the const variable to a #define macro, or it can't be done:

#include <stdio.h>

void f1(void){
    puts(__func__);
}

void f2(void){
    puts(__func__);
}

#define PASTE(f,n) f##n
#define USE(f,n) PASTE(f,n)

#define n 2

int main (void)
{
    USE(f,n)();  // this is btw a horrible poor way of writing C code
    return 0;
}

A saner and more readable solution would be a function pointer table:

typedef void func_t (void);

static func_t* const f[] = { f0, f1, f2 };
...
f[n]();
  • Related