Come usare #if all’interno di #define nel preprocessore C?

Voglio scrivere una macro che sputa il codice in base al valore booleano del suo parametro. Pertanto, DEF_CONST(true) deve essere espanso in const e DEF_CONST(false) deve essere espanso in nulla.

Chiaramente quanto segue non funziona perché non possiamo usare un altro preprocessore all’interno di #defines:

 #define DEF_CONST(b_const) \ #if (b_const) \ const \ #endif 

È ansible simulare condizionali utilizzando la concatenazione di token macro come segue:

 #define DEF_CONST(b_const) DEF_CONST_##b_const #define DEF_CONST_true const #define DEF_CONST_false 

Poi,

 /* OK */ DEF_CONST(true) int x; /* expands to const int x */ DEF_CONST(false) int y; /* expands to int y */ /* NOT OK */ bool bSomeBool = true; // technically not C :) DEF_CONST(bSomeBool) int z; /* error: preprocessor does not know the value of bSomeBool */ 

Inoltre, consentendo il passaggio dei parametri macro a DEF_CONST stesso (come correttamente sottolineato da GMan e altri):

 #define DEF_CONST2(b_const) DEF_CONST_##b_const #define DEF_CONST(b_const) DEF_CONST2(b_const) #define DEF_CONST_true const #define DEF_CONST_false #define b true #define c false /* OK */ DEF_CONST(b) int x; /* expands to const int x */ DEF_CONST(c) int y; /* expands to int y */ DEF_CONST(true) int z; /* expands to const int z */ 

Si può anche considerare il molto più semplice (anche se potenzialmente meno flessibile):

 #if b_const # define DEF_CONST const #else /*b_const*/ # define DEF_CONST #endif /*b_const*/ 

Farlo come una macro parametrizzata è un po ‘strano.

Perché non fare solo qualcosa del genere:

 #ifdef USE_CONST #define MYCONST const #else #define MYCONST #endif 

Quindi puoi scrivere un codice come questo:

 MYCONST int x = 1; MYCONST char* foo = "bar"; 

e se si compila con USE_CONST definito (ad es. tipicamente qualcosa -DUSE_CONST nelle opzioni makefile o del compilatore) allora userà i consts, altrimenti non lo farà.

Edit: In realtà vedo che Vlad ha coperto quell’opzione alla fine della sua risposta, quindi +1 per lui 🙂