16

このようなことをすることは可能ですか

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

SOMETHING が定義されている場合、foo(...) の呼び出しはコメント (または評価またはコンパイルされないもの) になり、それ以外の場合は MyFunction の呼び出しになります。

__noop が使用されているのを見たことがありますが、それを使用できるとは思いません。

編集:

MyFunction は可変数の引数を取るため、ここで実際にマクロを使用できるとは思いません。

また、引数が評価されないようにしたいと思います! (そのため、 MyFunction の本体をコメントアウトするようなことをしても、引数は引き続き評価されるため、実際には必要なものが得られません)

4

11 に答える 11

25

これを試して:

#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 & Pike The Practice of ProgrammingおよびGoddardを参照してください宇宙飛行センターのプログラミング標準

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 との互換性が問題にならない限り、新しいコードでは使用しないでください。

于 2009-02-13T18:04:29.300 に答える
5

これを行う簡単な方法は、関数の本体を条件付きで省略することでしょうか?

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

特に関数呼び出しをまったく行いたくない場合を除き、これは目標を達成するためのクリーンな方法のように思えます。

于 2009-02-13T18:04:57.287 に答える
3

残念ながら、現在の C++ バージョンは可変個引数マクロをサポートしていません。

ただし、これを行うことができます:

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

// you call it with double parens:
foo((a, b, c));
于 2009-02-13T19:08:34.483 に答える
2

foo を呼び出したくない場合は、次のように定義します。

void foo() {}

foo() への呼び出しは最適化する必要があります。

于 2009-02-13T19:01:47.120 に答える
2

これらの線に沿ったものはどうですか:

#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");
于 2009-02-13T19:08:18.150 に答える
1

マクロハッカーの使用が問題の原因になる可能性があるため、この回答を投稿するのは少し気が進まない. ただし非表示にしたい関数への呼び出しが常にステートメントで単独で使用される場合 (つまり、それらがより大きな式の一部ではない場合)、次のようなものが機能します (そして可変引数を処理します)。

#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 と Jonathan Leffler が提案したものに近いものです。

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

これは、コンパイラが可変長マクロをサポートする必要がないという点で少し異なります ( __VA_ARGS__)。

これは、通常は大きな式に結合されることのないデバッグ トレース関数呼び出しを排除するのに役立つと思いますが、それ以上に危険な手法だと思います。

問題が発生する可能性があることに注意してください。特に、呼び出しのパラメーターが副作用を引き起こす場合は注意してください (これはマクロの一般的な問題であり、このハックだけではありません)。この例では、がビルドで定義されているa++場合にのみ評価され、それ以外の場合は評価されません。SOMETHINGそのため、呼び出し後のコードがインクリメントされる の値に依存している場合a、ビルドの 1 つにバグがあります。

于 2009-02-14T08:29:33.900 に答える
1

いいえ、C および C++ 標準では、何かを #define してコメントにすることはできないと規定されているため、

#define foo //

動作しません。

于 2009-02-13T19:09:14.950 に答える
1
#ifdef SOMETHING
#define foo sizeof
#else
#define foo MyFunction
#endif

foo はprintfスタイル関数だと思いますか? いずれにせよ、これはゼロ パラメータ関数では機能しませんが、その場合、何をすべきかは既にわかっているはずです。あなたが本当にアナルになりたいなら、あなたは使うことができます(void)sizeofが、それはおそらく不必要です.

于 2009-02-13T19:12:08.717 に答える
0

myFunctionへの各呼び出しをで囲むのはどうですか

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

于 2009-02-13T20:42:30.217 に答える
0

私の記憶が正しければ、マクロを #define して "nothing" にすることができるはずです。これにより、コンパイラはその呼び出しを無視します。

#define foo()

foo();    // this will be ignored
于 2009-02-13T18:04:55.900 に答える