プログラムの stdout を /dev/null
にリダイレクトする場合 、 printf(3)
への呼び出し それでもすべての引数が評価され、文字列の書式設定プロセスは write(2)
を呼び出す前に行われます。 これは、フォーマットされた完全な文字列をプロセスの標準出力に書き込みます。データがディスクに書き込まれないのはカーネル レベルですが、特殊なデバイス /dev/null
に関連付けられたハンドラによって破棄されます。 .
したがって、最良の場合でも、引数を評価して printf
に渡すオーバーヘッドをバイパスまたは回避することはありません。 、printf
の背後にある文字列フォーマット ジョブ 、および標準出力を /dev/null
にリダイレクトするだけで、実際にデータを書き込む少なくとも 1 つのシステム コール .まあ、それは Linux での真の違いです。実装は、書き込みたいバイト数を返すだけです (write(2)
への呼び出しの 3 番目の引数で指定されます)。 )、他のすべてを無視します(この回答を参照)。書き込んでいるデータの量と、ターゲット デバイス (ディスクまたは端末) の速度によって、パフォーマンスの違いは大きく異なる場合があります。組み込みシステムでは、一般的に /dev/null
にリダイレクトしてディスク書き込みを遮断します かなりの量のデータを書き込むためにかなりのシステム リソースを節約できます。
理論的には、プログラムは /dev/null
を検出できますが、 一般的な実装の一般的な理解に基づいて、準拠する標準 (ISO C および POSIX) の制限内でいくつかの最適化を実行しますが、実際には実行していません (つまり、Unix または Linux システムがそうしていることを知りません)。
POSIX 標準では、printf(3)
へのすべての呼び出しに対して、標準出力への書き込みが義務付けられています。 、したがって、 write(2)
への呼び出しを抑制することは標準に準拠していません 関連するファイル記述子に応じて。 POSIX 要件の詳細については、Damon の回答を参照してください。ああ、簡単な注意:すべての Linux ディストリビューションは、認定されていませんが、実質的に POSIX に準拠しています。
printf
を置き換える場合は注意してください printf("%d%n", a++, &b)
のように、一部の副作用がうまくいかない場合があります。 .プログラムの実行環境に応じて出力を本当に抑制する必要がある場合は、グローバル フラグを設定し、printf をまとめて印刷前にフラグをチェックすることを検討してください。パフォーマンスの低下が目に見えるほどプログラムの速度を低下させることはありません。 、単一の条件チェックは 多く printf
を呼び出すよりも高速 すべての文字列の書式設定を行います。
printf
関数はします stdout
に書き込みます . /dev/null
の最適化に準拠していません .したがって、フォーマット文字列の解析と必要な引数の評価のオーバーヘッドが発生し、少なくとも 1 つの syscall が発生し、さらにバッファーをカーネル アドレス空間にコピーします (これは、syscall のコストと比較して無視できます)。 ).
この回答は、POSIX の特定のドキュメントに基づいています。
<ブロック引用>
システム インターフェース
dprintf、fprintf、printf、snprintf、sprintf - フォーマットされた出力を印刷します
fprintf() 関数は、指定された出力ストリームに出力を配置します。 printf() 関数は、標準出力ストリーム stdout に出力を配置します。 sprintf() 関数は、*s から始まる連続したバイトにヌル バイト '\0' が続く出力を配置します。十分なスペースを確保するのはユーザーの責任です。
基本定義
しなければならない
POSIX.1-2017 に準拠する実装の場合、必須の機能または動作について説明します。アプリケーションは、機能または動作の存在に依存できます。