Используйте #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

?