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]();