scanf_s()
は、C99標準(または以前のもの)では記述されていません。
C99(またはそれ以前)をターゲットとするコンパイラを使用する場合は、scanf()を使用します。 C11 Standard
の場合、buffer overflows
に対してセキュリティを強化するためにscanf_s()
はscanf()よりもはるかに難しいです。
したがって、基本的に2つの方法の違いは何ですか?
scanf_s()
は、より安全なバージョンのscanf()です。宛先を指定する引数の後に、宛先のサイズを指定する必要があります。プログラムは、コピーする前にバッファが指定されたサイズであることをチェックして、上書きがなく、悪意のあるコードが実行されていないことを確認します。引数はscanf_s()
の場合に渡される必要があります。
また、scanfの幅指定がバッファオーバーフローをブロックしている場合、元のscanfを「安全でない」と呼びますか?
scanf
で使用できるフォーマット指定子は、入力の最大サイズを制限し、バッファオーバーフローを防ぐ明示的なフィールド幅の設定をサポートしています。しかし、フィールド幅がembedded into format string
でなければならないので、scanf()
の機能は使いにくいです(printf
で実行できるように、可変引数を渡す方法はありません)。 scanfは実際にはそれほどうまく設計されていません。しかし、scanfが文字列バッファオーバーフローの安全性に関して何とか絶望的に壊れているという主張は完全に虚偽であり、通常は怠惰なプログラマによって作られています。
scanf()
の実際の問題は、あまりオーバーフローしているにもかかわらず、まったく異なる性質を持っています。 scanf関数を使用して数値の小数表現を算術型の値に変換すると、算術オーバーフローから保護されません。オーバーフローが発生した場合、scanfは未定義の動作を生成します。このため、C標準ライブラリで変換を実行する唯一の正しい方法は、strto
ファミリの関数です。
したがって、上記を要約すると、scanf
の問題は、文字列バッファで適切かつ安全に使用することが難しいということです。また、算術入力には安全に使用することはできません。後者は本当の問題です。前者は不便です。それはprintf
で行うことができるように
scanf_s
は(scanf()
フィールドの幅がembedded into format string
なければならない)、可変長引数を介してフィールド幅を通過させることによって、文字列の場合にバッファオーバーフローの問題を解決します。また、フィールド幅はscanf_s
では必須ですが、scanf
ではオプションです。
ありがとうございます。しかしもう1つの疑問は、算術オーバーフローからscanf_sは安全ですか? scanf_sはこの問題をどのように解決しましたか? – Gear
私は自分の答えを編集しました。 – abhiarora
C標準の関数 'scanf_s()'は数値入力の算術オーバーフロー(アンダーフロー)に対する保護を提供していないことに注意してください。少なくとも 'scanf C11規格のK.3.5.3.2。 –