Используйте #ifdefs и #define, чтобы по желанию включить вызов функции в комментарий
Можно ли сделать что-то вроде этого
#ifdef SOMETHING
#define foo //
#else
#define foo MyFunction
#endif
Идея состоит в том, что если SOMETHING определен, тогда вызовы foo (...) становятся комментариями (или что-то, что не оценивается или компилируется), в противном случае он становится вызовом MyFunction.
Я видел __noop, но я не верю, что смогу это использовать.
ИЗМЕНИТЬ (ы):
Я не думаю, что могу реально использовать макрос здесь, потому что MyFunction принимает переменное количество аргументов.
Кроме того, я хотел бы сделать так, чтобы аргументы НЕ оценивались! (Так что делать что-то вроде комментирования тела MyFunction, на самом деле не дает мне то, что мне нужно, поскольку аргументы все равно будут оцениваться)
Ответы
Ответ 1
Попробуйте следующее:
#ifdef SOMETHING
#define foo(x)
#else
#define foo(x) MyFunction(x)
#endif
Если ваша функция имеет несколько аргументов, то:
#ifdef SOMETHING
#define foo(x,y,z)
#else
#define foo(x,y,z) MyFunction(x,y,z)
#endif
Если ваша функция имеет переменное количество аргументов, ваш компилятор может поддерживать так называемые "переменные макросы", например:
#ifdef SOMETHING
#define foo(...)
#else
#define foo(...) MyFunction(__VA_ARGS__)
#endif
Причина, по которой я видел такую вещь, которая используется на практике, состоит в том, чтобы избавиться от функций регистрации из сборки релиза. Однако см. Также Разделить "отлаживать" и "выпускать" сборки?, в которых люди задаются вопросом, должны ли вы даже иметь разные сборки.
В качестве альтернативы вместо того, чтобы переопределять вызов функции как ничего, комментарий Джонатана к этому ответу предложил сделать что-то вроде следующего:
#ifdef SOMETHING
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
#else
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
#endif
Причиной этого является то, что вызов функции всегда скомпилирован (поэтому он не будет оставлен с безвозвратными ошибками, как ссылки на удаленные переменные), но вызывается только при необходимости: см. Kernighan and Pike Практика программирования, а также Стандарты программирования Центра космических полетов Годдарда.
Из файла debug.h(начиная с 1990 года и, следовательно, не используя __VA_ARGS__
):
/*
** Usage: TRACE((level, fmt, ...))
** "level" is the debugging level which must be operational for the output
** to appear. "fmt" is a printf format string. "..." is whatever extra
** arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#ifdef DEBUG
#define TRACE(x) db_print x
#else
#define TRACE(x) do { if (0) db_print x; } while (0)
#endif /* DEBUG */
С C99 больше нет необходимости в трюке с двойными скобками. Новый код не должен использовать его, если проблема с C89 не является проблемой.
Ответ 2
Может быть, более простой способ сделать это - условно опустить тело функции?
void MyFunction() {
#ifndef SOMETHING
<body of function>
#endif
}
Если вы специально не хотите, чтобы вызов функции выполнялся вообще, это кажется чистым способом достижения вашей цели.
Ответ 3
К сожалению, текущая версия С++ не поддерживает переменные макросы.
Однако вы можете сделать это:
#ifdef SOMETHING
#define foo
#else
#define foo(args) MyFunction args
#endif
// you call it with double parens:
foo((a, b, c));
Ответ 4
Если в случае, если вы не хотите, чтобы вызвал foo, вы определяете его как:
void foo() {}
любые вызовы foo() должны быть оптимизированы.
Ответ 5
Что-то в этом роде:
#ifdef NDEBUG
#define DEBUG(STATEMENT) ((void)0)
#else
#define DEBUG(STATEMENT) (STATEMENT)
#endif
Вы должны использовать его так, чтобы регистрировать отладочные сообщения:
DEBUG(puts("compile with -DNDEBUG and I'm gone"));
Нестандартная версия для форматированного вывода с дополнительной информацией об отладке с использованием вариативных макросов C99 и идентификатора __func__
может выглядеть следующим образом:
#ifdef NDEBUG
#define Dprintf(FORMAT, ...) ((void)0)
#define Dputs(MSG) ((void)0)
#else
#define Dprintf(FORMAT, ...) \
fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \
__func__, __FILE__, __LINE__, __VA_ARGS__)
#define Dputs(MSG) Dprintf("%s", MSG)
#endif
Здесь вы можете использовать эти макросы:
Dprintf("count = %i", count);
Dputs("checkpoint passed");
Ответ 6
Вероятно, вы не хотите делать простой "удаление кода", как это было предложено,
потому что ваши абоненты будут ожидать побочных эффектов
аргументы. Вот некоторые хлопотные фрагменты
вы должны подумать:
// pre/post increment inside method call:
MyFunction(i++);
// Function call (with side effects) used as method argument:
MyFunction( StoreNewUsernameIntoDatabase(username) );
Если бы вы отключили MyFunction, просто сказав:
#define MyFunction(x)
тогда побочные эффекты, ожидаемые абонентами, исчезнут,
и их код сломается, и его будет довольно сложно отлаживать. мне нравится
предложение "sizeof" выше, и мне также нравится предложение просто
отключите тело MyFunction() через # ifdef, хотя это означает
что все вызывающие абоненты получают одну и ту же версию MyFunction(). От твоего
я предполагаю, что на самом деле вы не хотите.
Если вам действительно нужно отключить MyFunction() с помощью препроцессора,
для каждого исходного файла, тогда я бы сделал это следующим образом:
#ifdef SOMETHING
#define MyFunction(x) NoOp_MyFunction(x)
int NoOp_MyFunction(x) { }
#endif
Вы даже можете включить реализацию NoOp_MyFunction() внутри
источник и заголовки для MyFunction(). У вас также есть гибкость
добавить дополнительную запись или отладочную информацию в NoOp_MyFunction() как
хорошо.
Ответ 7
Нет, стандарты C и С++ говорят, что вы не можете #define что-то быть комментарием, поэтому
#define foo //
не будет работать.
Ответ 8
#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif
Я предполагаю, что foo - это функция стиля printf
? В любом случае, это не будет работать с нулевой функцией параметра, но если это так, вы уже знаете, что делать. Если вы действительно хотите быть анальным, вы можете использовать (void)sizeof
, но это, вероятно, не нужно.
Ответ 9
Я немного неохотно публикую этот ответ, потому что использование макроса хакера может стать источником проблем. Тем не менее - , если вызовы функции, которые вы хотите удалить, всегда используются отдельно в инструкции (т.е. Они никогда не являются частью более крупного выражения), тогда может работать что-то вроде следующего (и он обрабатывает varargs):
#ifdef SOMETHING
#define foo (1) ? ((void) 0) : (void)
#else
#define foo MyFunction
#endif
Итак, если у вас есть строка кода:
foo( "this is a %s - a++ is %d\n", "test", a++);
он закончится после этапа предварительной обработки как:
MyFunction( "this is a %s - a++ is %d\n", "test", a++);
или
(1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);
который превращает список параметров псевдофункции в кучу выражений, разделенных оператором запятой, который никогда не будет оценен, поскольку условие всегда возвращает результат ((void) 0)
.
Вариант этого - нечто близкое к тому, что предложил ChriSW и Джонатан Леффлер:
#ifdef SOMETHING
#define foo if (0) MyFunction
#else
#define foo if (1) MyFunction
#endif
Это немного отличается тем, что компилятор не поддерживает переменные макросы (__VA_ARGS__
).
Я думаю, что это может быть полезно для устранения вызовов функции отладки трассировки, которые, как правило, никогда не объединяются в большее выражение, но помимо этого я считаю это опасной техникой.
Обратите внимание на потенциальные проблемы - особенно если параметры вызова вызывают побочные эффекты (это общая проблема с макросами - не только этот хак). В этом примере a++
будет оцениваться только в том случае, если в сборке определен SOMETHING
, иначе это не так. Поэтому, если код после вызова зависит от значения a
, который должен быть увеличен, один из сборок имеет ошибку.
Ответ 10
Если я правильно помню, вы должны иметь возможность #define вашего макроса на "ничего", и это заставит компилятор игнорировать этот вызов
#define foo()
foo(); // this will be ignored
Ответ 11
Как насчет окружающего каждого вызова myFunction с помощью
#ifdef SOMETHING
myFunction(...);
#endif
?