関数を無音にすることは可能ですか? 例えば:
#include <stdio.h>
int function(){
printf("BLAH!");
return 10;
}
int main(){
printf("%d", silence( function()) );
return 0;
}
そして代わりに:
BLAH!
10
私は得るでしょう:
10
出来ますか?肯定的な場合、それを行う方法は?
たいていのことを行うための非常に複雑な方法は、dup2()システム コールを使用することです。これには、 が呼び出されるfflush(stdout); dup2(silentfd, stdout);
前に実行function()
し、後でコピーする必要があります: fflush(stdout); dup2(savedstdoutfd, stdout);
。したがってsilence(function())
、この構文は が実行された後にしかコードを実行できないため、 as just を実行することはできませんfunction()
。
ファイル記述子は事前に準備する必要がsilentfd
ありsavedstdoutfd
ます (テストされていないコード):
int silentfd = open("/dev/null",O_WRONLY);
int savedstdoutfd = dup(stdout);
これはほぼ間違いなくあなたが本当に望んでいることではありませんが、あなたの質問が「可能ですか?」と表現されている限り、答えは「ほぼ」です。
マクロ機能とヌルデバイスを使用してください。
たとえば、Windows の場合
#include <stdio.h>
#define silence(x) (_stream = freopen("NUL:", "w", stdout), _ret_value = x,_stream = freopen("CON:", "w", stdout),_ret_value)
int _ret_value;
FILE *_stream;
int function(){
printf("BLAH!");
return 10;
}
int main(void){
printf("%d", silence( function()) );
return 0;
}
printf
印刷を防止する代わりに、このマクロを使用できます。
int flag=0;
#define PRINT(...) if(flag){printf(...)}
次に、変数を考慮して PRINT マクロを使用しますflag
。の場合flag==1
、関数は印刷され、 の場合、関数は印刷されflag==0
ません。
いいえ、それは不可能です。ただし、stdout を一時的に別のものにリダイレクトすることもできます。それはあなたが望むものに近づくかもしれません。
GCC 拡張機能を使用すると、次のようなマクロを使用することを検討できます。
bool silent;
#define silence(X) ({int _x; quiet(); _x = (X); verbose(); _x; })
#define printf(Fmt,...) \
do{if (!silent) printf(Fmt,##__VA_ARGS__);}while(0)
そのsilence
マクロは、その引数X
がint
式である (またはtypeofを使用する)場合にのみ機能しますprintf
。「再帰的」マクロは特別に前処理されていることを思い出してください。printf
(そのprintf
マクロ内の) の内部オカレンスは、マクロ展開なしで逐語的に残されます。
を関数にすることsilence
はできません (そうでない場合、関数を呼び出す前に引数が評価されます)。そして、マクロ呼び出しの値として返すために、いくつかの変数の引数の結果を「記憶」するためのGCCステートメント式拡張が必要です_x
(プリプロセッサ連結を使用してその名前を生成できます)。__COUNTER__
silence
次に、関数を定義する必要がquiet()
ありverbose()
、おそらく次のようなものです
void quiet()
{
silent = true;
}
void verbose()
{
silent = false,
}
printf
マクロとして定義したくない場合は、 freopen(3) on stdout
(おそらく"/dev/null"
etc...) を使用するか、dup2(2)トリックを実行できます ( Pascal Cuoq が提案するように)。
コード ベースが巨大で、より本格的なものが必要で、数日または数週間の作業を喜んで行う場合は、プラグインまたはMELT拡張機能を使用して GCC コンパイラをカスタマイズすることを検討してください (または誰かに依頼してください)。printf
GCC に認識されていることに注意してください。
実際には、次のような独自のマクロを定義する必要があります
#define myprintf(Fmt, ...) do{if (!silent) \
printf(Fmt,__VA_ARGS__);}while(0)
myprintf
どこでも代わりに使用するだけでprintf
、これは移植可能なトリックです。もちろん、printf
関数ポインタとして渡していないと思います。
デバッグには、実際にお勧めします
#define dbgprintf(Fmt,...) do{if (wantdebug) \
printf("%s:%d:" Fmt "\n", __FILE__, __LINE__, \
##__VA_ARGS__);}while(0)
そして、dbgprintf("i=%d",i)
単にdbgprintf("foo here")
コード内で or を使用します。
可変引数マクロへの変数引数を受け入れない##__VA_ARGS__
ために、GCC 拡張機能である which を使用しています。厳密な C99 が必要な場合は、and everyと言うだけで、フォーマットの後に 1 つの引数が必要になります。__VA_ARGS__
dbgprintf
独自の関数を再実装することもできますprintf
が、それはお勧めしません。
(物事はもっと複雑になる可能性があることに注意してください。not ... を使用して印刷できfputs
ます。 printf
)
残念ながら、関数を明示的に印刷してこのように呼び出すと、常に印刷されます。関数を完全に沈黙させたい場合は、その行をコメントアウトするだけです。制御ステートメントを使用して、IFのみを出力し、条件が満たされた場合にのみ出力することもできます。