#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>}
)?
- По возможности совместим с стандартом
Ответы
Ответ 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
})
)