私はこれを多くの場所で読みましたが、理解できません。cout が printf() よりも型安全であると言われる理由 書く必要がない%d %c %f
か、より深い意味があるからです。
前もって感謝します。
これが理由です:
printf("%s\n", 42); // this will clobber the stream
printf
これにより、バッファ オーバーフローが発生します。通常、コンパイラは、最初の引数の書式文字列が後続の引数の型に対応しているかどうかを確認できません。上記の場合、文字列がハードコードされているため、これを行うことができますが、一部のコンパイラはそうしています。1しかし、一般に、フォーマット文字列は実行時に決定される可能性があるため、コンパイラはその正確性をチェックできません。
1しかし、これらのチェックは特殊なケースprintf
です。myprintf
と同じシグネチャで独自の関数を作成した場合、シグネチャは関数内のすべての型情報を省略する省略記号を使用するため、型の安全性をチェックする方法はありませんprintf
。...
型システムは の正しさを保証しますが、保証しstd::ostream
ませんprintf
。コンラッドの答えは一例ですが、
printf("%ld\n", 7);
も壊れています (システム上でlong
とint
が異なるサイズであると仮定します)。あるビルド ターゲットでは機能し、別のビルド ターゲットでは失敗することさえあります。typedef を印刷しようとするとsize_t
、同じ問題が発生します。
これは、一部のコンパイラが提供する診断によって (ある程度) 解決されますが、2 つ目の意味では役に立ちません。
両方の型システム (書式文字列で使用される実行時の型システムと、コードで使用されるコンパイル時の型システム) を自動的に同期させることはできません。たとえば、printf
テンプレートとのやり取りがうまくいきません。
template <typename T> void print(T t) { printf("%d\n",t); }
これをすべての型に対して正しくすることはできませT
ん。できることはstatic_cast<int>(t)
、T が int に変換できない場合にコンパイルに失敗することです。比較
template <typename T> void print(std::ostream& os, T t) { os << t << '\n'; }
の正しいオーバーロードを選択しoperator<<
ますT
。