#if 0 как определение - PullRequest
       37

#if 0 как определение

12 голосов
/ 10 февраля 2010

Мне нужен способ определения макроса FLAGS_IF (или его эквивалента) таким, чтобы

FLAGS_IF(expression)
<block_of_code>
FLAGS_ENDIF

при компиляции в отладке (например, с определенным переключателем компилятора) компилируется в

if (MyFunction(expression))
{
    <block_of_code>
}

тогда как в релизе не приведено ни одной инструкции, как это было

#if 0
    <block_of_code>
#endif

Из-за моего невежества по поводу препроцессоров C / C ++ я не могу придумать какой-либо наивный способ (поскольку #define FLAGS_IF(x) #if 0 даже не компилируется) сделать это, вы можете помочь?

Мне нужно решение, которое:

  • Не запутывается, если */ присутствует внутри <block_of_code>
  • Обязательно генерирует 0 инструкций в релизе даже внутри встроенных функций на любой глубине (я думаю, это исключает if (false){<block_of_code>} верно?)
  • Соответствует стандарту, если это возможно

Ответы [ 6 ]

30 голосов
/ 10 февраля 2010

Макросы довольно злые, но нет ничего более злого, чем запутывание управляющих операторов и блоков макросами. Нет веских причин для написания такого кода. Просто сделайте это:

#ifdef DEBUG
  if (MyFunction(expression))
  {
    <block_of_code>
  }
#endif
12 голосов
/ 10 февраля 2010

Следующее должно делать то, что вы хотите:

#ifdef DEBUG
# define FLAGS_IF(x) if (MyFunction((x))) {
# define FLAGS_ENDIF }
#else
# define FLAGS_IF(x) if(0) {
# define FLAGS_ENDIF }
#endif

if (0) не должно превращаться в инструкции или, по крайней мере, в большинстве компиляторов.

Редактировать : Хастуркун отметил, что вам действительно не нужен FLAGS_ENDIF, поэтому вместо этого вы должны написать свой код так:

FLAGS_IF(expression) {
   <block_of_code>
}

со следующими макросами:

#ifdef DEBUG
# define FLAGS_IF(x) if (MyFunction((x)))
#else
# define FLAGS_IF(x) if(0)
#endif
7 голосов
/ 10 февраля 2010

Я мог бы сделать что-то вроде:

#ifdef DEBUG
const bool IS_RELEASE_MODE = false;
#else
const bool IS_RELEASE_MODE = true;
#endif

if (IS_RELEASE_MODE && MyFunction(expression))
{
    ...
}

Это должно быть скомпилировано из сборок релиза, потому что if (false && f ()) совпадает с if (false), что оптимизируется в большинстве компиляторов.

Это если вы настаиваете на том, чтобы не использовать #ifdef внутри вашего кода. В противном случае, я бы предпочел #ifdef DEBUG if (MyFunction (expression)) {...} #endif, который кто-то еще опубликовал.

4 голосов
/ 10 февраля 2010

Почему вы не можете использовать следующее?

#ifdef DEBUG
code for debug mode
#else
code for release mode
#endif
3 голосов
/ 10 февраля 2010

Обычно я стараюсь избегать слишком частого использования условной компиляции, когда это возможно.

Во-первых, это обычно некрасиво и менее читабельно.

Но что еще более важно, когда проекты используют условную компиляцию для включения и выключения кода отладки, я иногда сталкиваюсь с проблемами, когда код отладки становится устаревшим, когда он отключен. Затем, когда я хочу использовать код для отладки, я включаю его и ... все. Не. Построить. Anymore.

Код отладки может ссылаться на переменные или функции, которые больше не существуют, или что-то вокруг скрытого кода отладки иным образом изменилось настолько, что это просто больше не синтаксически допустимо.

Это может быть очень раздражающим.

Итак, я лично избегал условной компиляции для включения / выключения кода отладки в пользу использования перечисления или макроса (который все еще условно компилируется) для использования в качестве условия в операторе if. При компиляции как if (0) код времени выполнения не генерируется - именно так, как требуется. Но код все еще компилируется и проверяется синтаксис, поэтому он всегда по крайней мере синтаксически корректен.

#if NDEBUG  // using the same standard macro that `assert()` uses
            //  use your own if NDEBUG doesn't make sense
enum {
    DebugOn = 0
}
#else
enum {
    DebugOn = 1
}
#endif


// ... elsewhere

if (DebugOn) {
    // this always gets compiled, but if it's a release build
    //  the compiler will not emit anything...
}

Как упомянул FryGuy , вы можете легко комбинировать это с вызовом вашего MyFunction(), если хотите - в сборке релиза функция не будет вызываться из-за короткого замыкания, каковым является ваше поведение Оговаривается:

if (DebugOn && MyFunction( expression)) {
    // this always gets compiled, but if it's a release build
    //  the compiler will not emit anything...
}

Но лично я бы, наверное, использовал

if (DebugOn) {
    if (MyFunction( expression)) {
        // ... 
    }
}

Что, я думаю, помогает немного яснее (чуть-чуть) сказать, что это блок только для отладки.

Это имеет то преимущество, что всегда компилируется и не имеет контроля потока, спрятанного за макросами (что несколько других ответов назвали злом).

2 голосов
/ 10 февраля 2010

Как насчет этого:

#ifdef DEBUG
#define FLAGS_IF(expr, block) { if (MyFunction(expr)) block }
#else
#define FLAGS_IF(expr, block)
#endif

Вы можете использовать это так:

FLAGS_IF(your_favourite_expression,
  ({
     // some code
  })
)
...