web-dev-qa-db-fra.com

Comment utiliser #if dans #define dans le préprocesseur C?

Je veux écrire une macro qui crache du code en fonction de la valeur booléenne de son paramètre. Disons que DEF_CONST(true) devrait être développé en const et DEF_CONST(false) devrait être développé en rien.

De toute évidence, ce qui suit ne fonctionne pas car nous ne pouvons pas utiliser un autre préprocesseur dans #defines:

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

Vous pouvez simuler des conditions en utilisant concaténation de jetons de macro comme suit:

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

Ensuite,

/* 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 */

En outre, en permettant de passer des paramètres de macro à DEF_CONST lui-même (comme indiqué correctement par GMan et d'autres):

#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 */

Vous pouvez également considérer le plus simple (bien que potentiellement moins flexible):

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

Le faire comme une macro paramétrisée est un peu étrange.

Pourquoi ne pas simplement faire quelque chose comme ça:

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

Ensuite, vous pouvez écrire du code comme ceci:

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

et si vous compilez avec USE_CONST défini (par exemple, généralement quelque chose -DUSE_CONST dans les options du makefile ou du compilateur) alors il utilisera les consts, sinon il ne le fera pas.

Edit: En fait, je vois que Vlad a couvert cette option à la fin de sa réponse, alors +1 pour lui :)

7
GrahamS