[解決済み] 標準ライブラリで避けるべき関数は何ですか?
質問
Stack Overflow で、いくつかの C 関数は "obsolete" または "should be avoided" と書いてありました。この種の関数のいくつかの例とその理由を教えてください。
そのような関数の代替となるものは何ですか?
それらを安全に使用することはできますか - 何か良い方法はありますか?
どのように解決するのですか?
非推奨の関数
安全でない
このような関数の完全な例として
gets()
で、これは宛先バッファの大きさを伝える方法がないためです。その結果、gets()を使って入力を読み取るプログラムは
バッファオーバーフローの脆弱性
. 同様の理由で
strncpy()
の代わりに
strcpy()
と
strncat()
の代わりに
strcat()
.
さらにいくつかの例では tmpfile() や mktemp() 関数に起因する 一時ファイルを上書きすることによる潜在的なセキュリティ問題 であり、より安全な mkstemp() 関数に取って代わられました。
非リーエントラント
その他の例としては
gethostbyaddr()
と
gethostbyname()
はリエントラントでない (したがってスレッドセーフであることが保証されていない) ため、リエントラントの
getaddrinfo()
と
freeaddrinfo()
.
セキュリティの欠如 (おそらく署名に十分な情報を含めることができず、安全に実装できない) や再入可能性の欠如が、非推奨の一般的な原因です。
時代遅れ、非移植可能
他のいくつかの関数は、単に機能が重複していたり、他の亜種と比較して移植性が低いために非推奨となります。たとえば
bzero()
は非推奨となり、代わりに
memset()
.
スレッドセーフとリエントランス
あなたは投稿の中で、スレッドセーフと再入力について尋ねました。わずかな違いがあります。関数は、共有され、変更可能な状態を使用しない場合、リエントラントです。例えば、必要な情報がすべて関数に渡され、必要なバッファも(関数へのすべての呼び出しで共有されるのではなく)関数に渡される場合、それはリエントラントです。つまり、異なるスレッドが独立したパラメータを使用することで、誤って状態を共有するリスクを回避することができるのです。再入可能性は、スレッドセーフよりも強力な保証である。複数のスレッドが同時に使用できる場合、その関数はスレッドセーフです。関数は、以下の場合にスレッドセーフです。
- リエントラントである (すなわち、呼び出しの間で状態を共有しない)、または。
- リエントラントではないが、共有状態のために必要に応じて同期/ロックを使用する。
一般に 単一の UNIX 仕様 と IEEE 1003.1 (すなわち POSIX") では、リエントラントであることが保証されていない関数は、スレッドセーフであることが保証されません。つまり、リエントラントであることが保証されている関数だけが、(外部ロックなしで)マルチスレッドアプリケーションで移植的に使用することができるのです。しかし、これらの規格の実装が、リエントラントでない関数をスレッドセーフにすることを選択できないわけではありません。たとえば、Linux では、スレッドセーフの保証 (Single UNIX 仕様を超える) を追加するために、リエントラントでない関数に同期を頻繁に追加しています。
文字列 (および一般的なメモリ バッファ)
また、文字列や配列に何か根本的な欠陥があるのではないかという質問もありました。そのように主張する人もいるかもしれませんが、私は「いいえ、言語には根本的な欠陥はありません」と主張します。CとC++では、配列の長さ/容量を個別に渡す必要があります(他のいくつかの言語のように".length"のプロパティではありません)。これは、それ自体、欠陥ではありません。CやC++の開発者であれば、必要なところで長さをパラメータとして渡すだけで、正しいコードを書くことができます。問題は、この情報を必要とするいくつかのAPIが、それをパラメータとして指定しなかったことです。あるいは、何らかの MAX_BUFFER_SIZE 定数が使用されると仮定していました。このようなAPIは現在では非推奨となり、配列/バッファ/文字列のサイズを指定できる代替APIに置き換えられています。
スキャンフ (最後の質問への回答)
個人的には、C++ の iostreams ライブラリ (std::cin, std::cout, << と >> 演算子, std::getline, std::istringstream, std::ostringstream 等) を使用しているので、通常これを扱うことはありません。しかし、もし純粋な C 言語を使わざるを得ないとしたら、私個人としては、単に
fgetc()
または
getchar()
と組み合わせて
strtol()
,
strtoul()
などのように、手動でパースしています。とはいえ、私の知る限りでは、以下のような問題はないようです。
[f]scanf()
,
[f]printf()(プリントエフ
などのように、フォーマット文字列を自分で作成し、任意のフォーマット文字列を渡したり、ユーザ入力がフォーマット文字列として使われることを決して許したりせず、そして
で定義されているフォーマット・マクロを使用します。
で定義されているフォーマットマクロを適切に使用することです。(注意
snprintf()
の代わりに
sprintf()
の代わりにを使うべきですが、これは宛先バッファのサイズを指定しなかったことと関係があり、フォーマット文字列の使用とは関係ありません)。また、C++の場合、指摘しておかなければならないのは
boost::format
は、可変長引数なしで printf のような書式を提供します。
関連
-
[C] レポートエラー 代入の左オペランドとしてlvalueが必要
-
VSCodeでCプログラムを書くとエラーになる:ソースファイル "stdio.h" を開くことができない
-
[解決済み] c または c++ 用のシンプルな 2 次元クロスプラットフォームグラフィックスライブラリ?[クローズド]
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] 配列の場合、なぜ a[5] == 5[a] になるのでしょうか?
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] なぜC言語では構造体を頻繁にtypedefする必要があるのですか?
-
[解決済み] フリーは、どのように無料化を知っているのですか?
-
[解決済み】標準ライブラリを使ってアライメントされたメモリのみを割り当てるには?
-
[解決済み】size_tとuintptr_tの比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
g++が内部・外部コマンドソリューションとして認識されない、MinGWを初めて使うときの落とし穴
-
[C] レポートエラー 代入の左オペランドとしてlvalueが必要
-
未定義の `__isoc99_sscanf' への参照
-
[解決済み] Valgrind が初期化されていないバイトについて警告する
-
[解決済み] Windows用Cコンパイラ?[クローズド]
-
[解決済み] CコードでEOFを表現する?
-
[解決済み] ソケットアクセプト - "開かれているファイルが多すぎる"
-
[解決済み] mallocの結果はキャストするのですか?
-
[解決済み] C言語で配列のサイズを決定するにはどうすればよいですか?
-
[解決済み] C 言語の配列へのポインタ/ポインタの配列の曖昧さ解消