Как использовать #if внутри #define в препроцессоре C? - PullRequest
44 голосов
/ 14 мая 2010

Я хочу написать макрос, который выплевывает код на основе логического значения его параметра. Так, скажем, DEF_CONST(true) должен быть расширен до const, а DEF_CONST(false) должен быть расширен до нуля.

Очевидно, что следующее не работает, потому что мы не можем использовать другой препроцессор внутри #defines:

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

Ответы [ 2 ]

48 голосов
/ 14 мая 2010

Вы можете смоделировать условные выражения, используя сцепление макротокенов следующим образом:

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

Тогда

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

Также, позволяя передавать макропараметры в сам DEF_CONST (как правильно указал GMan и другие):

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

Вы также можете рассмотреть гораздо более простую (хотя потенциально менее гибкую):

#if b_const
# define DEF_CONST const
#else /*b_const*/
# define DEF_CONST
#endif /*b_const*/
7 голосов
/ 14 мая 2010

Делать это как парамтеризованный макрос немного странно.

Почему бы просто не сделать что-то вроде этого:

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

Тогда вы можете написать такой код:

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

и если вы скомпилируете с определенным USE_CONST (например, обычно что-то -DUSE_CONST в опциях makefile или compiler), то он будет использовать consts, иначе не будет.

Редактировать: На самом деле я вижу, что Влад закрыл этот вариант в конце своего ответа, поэтому +1 для него:)

...