Подтвердить что ты не робот

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

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

FLAGS_IF(expression)
<block_of_code>
FLAGS_ENDIF

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

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

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

#if 0
    <block_of_code>
#endif

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

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

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

Ответ 1

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

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

Если (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

Ответ 2

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

#ifdef DEBUG
  if (MyFunction(expression))
  {
    <block_of_code>
  }
#endif

Ответ 3

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

#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 (выражение)) {...} #endif, чтобы кто-то еще опубликовал.

Ответ 4

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

#ifdef DEBUG
code for debug mode
#else
code for release mode
#endif

Ответ 5

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

Во-первых, он обычно уродливый и менее читаемый.

Но, что еще более важно, когда проекты используют условную компиляцию для включения и отключения кода отладки, я иногда сталкиваюсь с проблемами, которые вызывают устаревание кода отладки при его отключении. Затем, когда я хочу использовать его для отладки кода, я включаю его и... Вещи. Не. Построить. 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 a release build
    //  the compiler will not emit anything...
}

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

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

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

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

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

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

Ответ 6

Как насчет чего-то вроде этого:

#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
  })
)