Используйте #ifdefs и #define, чтобы при необходимости превратить вызов функции в комментарий

можно ли сделать что-то подобное

#ifdef SOMETHING
#define foo //
#else
#define foo MyFunction
#endif

идея в том, что если что-то определено, то вызывает foo(...) стать комментариями (или чем-то, что не оценивается или не компилируется), иначе это становится вызовом MyFunction.

Я видел _ _ noop используется, но я не думаю, что могу использовать это.

изменить(ы):

Я не думаю, что я действительно могу использовать макрос здесь, потому что MyFunction принимает переменное число аргументы.

кроме того, я хотел бы сделать так, чтобы аргументы не оценивались! (Поэтому делать что-то вроде комментирования тела MyFunction на самом деле не дает мне то, что мне нужно, так как аргументы все равно будут оценены)

11 ответов


попробуйте это:

#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

причина, по которой я видел, что такие вещи используются на практике, - это избавиться от функций ведения журнала из сборки выпуска. Однако Смотрите также отдельные сборки "debug" и "release"? в котором люди спрашивают, вы должны даже есть различные сборки.


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

#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 & Pike в Практика программирования и Goddard Space Flight Center стандарты программирования.

из отладка.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 не является проблемой.


может быть, более простой способ сделать это было бы условно опустить тело функции?

void MyFunction() {
#ifndef SOMETHING
    <body of function>
#endif
}

Если вы специально не хотите, чтобы вызов функции был сделан вообще, это кажется чистым способом достижения вашей цели.


к сожалению, текущая версия C++ не поддерживает переменные макросы.

однако, вы можете сделать это:

#ifdef SOMETHING
#define foo
#else
#define foo(args) MyFunction args
#endif

// you call it with double parens:
foo((a, b, c));

Если в случае, если вы не хотите вызывать foo, вы определяете его как:

void foo() {}

любые вызовы foo () должны быть оптимизированы.


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

#ifdef NDEBUG
#define DEBUG(STATEMENT) ((void)0)
#else
#define DEBUG(STATEMENT) (STATEMENT)
#endif

вы бы использовали его так, чтобы регистрировать отладочные сообщения:

DEBUG(puts("compile with -DNDEBUG and I'm gone"));

не-универсальный вариант для форматированного вывода дополнительной отладочной информации, используя С99 макросы с переменным числом аргументов и __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");

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

// pre/post increment inside method call:
MyFunction(i++); 

// Function call (with side effects) used as method argument: 
MyFunction( StoreNewUsernameIntoDatabase(username) ); 

Если бы вы отключили MyFunction, просто сказав:

#define MyFunction(x) 

тогда побочные эффекты, которые абоненты ожидали бы уйти, и их код сломается, и будет довольно трудно отлаживать. Мне нравится в "размер" предложение выше, и мне также нравится предложение просто отключите тело MyFunction () через #ifdef, хотя это означает что все абоненты получают одну и ту же версию MyFunction(). От вашего постановка проблемы, я полагаю, это не то, чего вы хотите.

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

#ifdef SOMETHING 
#define MyFunction(x) NoOp_MyFunction(x) 

int NoOp_MyFunction(x) { } 
#endif 

вы даже можете включить реализацию NoOp_MyFunction () внутри этот исходные & заголовки для MyFunction (). У вас также есть гибкость чтобы добавить дополнительную информацию журнала или отладки в NoOp_MyFunction () как что ж.


нет, стандарты C и C++ говорят, что вы не можете #определить что-то как комментарий, поэтому

#define foo //

не работает.


#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif

Я предполагаю, что фу-это printf функции стиля? В любом случае, это не будет работать с функцией параметра ноль, но если бы это было так, вы бы уже знали, что делать. Если вы действительно хотите быть анальным, вы можете использовать (void)sizeof но это, вероятно, не нужно.


я немного неохотно публиковать этот ответ, потому что использование макро-хакерства может стать источником проблем. Тем не менее - если вызовы функции, которую вы хотите удалить, всегда используются отдельно в операторе (т. е., они никогда не являются частью большего выражения), тогда может работать что-то вроде следующего (и он обрабатывает 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) результат.

вариант этого близок к тому, что предложили Крису и Джонатан Леффлер:

#ifdef SOMETHING
#define foo if (0) MyFunction
#else
#define foo if (1) MyFunction
#endif

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

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

обратите внимание на потенциал проблем - особенно если параметры в вызове производят побочные эффекты (это общая проблема с макросами-не только этот хак). В Примере a++ будет оцениваться только если SOMETHING определен в сборке, в противном случае это не так. Поэтому, если код после вызова зависит от значения a для увеличения одна из сборок имеет ошибку.


Если я правильно помню, вы должны иметь возможность #определить свой макрос на "ничего", и это заставит компилятор игнорировать этот вызов

#define foo()

foo();    // this will be ignored

Как насчет окружения каждого вызова myFunction с

#ifdef SOMETHING
myFunction(...);
#endif

?