10

以下は、従来のシステムで最も一般的なstrcpyの実装です。destとsrcが最初にNULLについてチェックされないのはなぜですか?昔はメモリが限られていたので、ショートコードが常に好まれていたと聞いたことがあります。今日の開始時にNULLポインターチェックを使用してstrcpyおよびその他の同様の関数を実装しますか?なぜだめですか?

char *strcpy(char *dest, const char *src)
{
   char *save = dest;
   while(*dest++ = *src++);
   return save;
}
4

9 に答える 9

20

NULLは悪いポインタですが、そうです(char*)0x1。それもチェックする必要がありますか?私の意見では (決定的な理由はわかりません)、このような低レベルの操作での健全性チェックは必要ありません。strcpy()は非常に基本的なものであるため、asm 命令のように扱う必要があり、必要に応じて呼び出し元で独自の健全性チェックを行う必要があります。ちょうど私の2セント:)

于 2010-09-01T08:45:33.743 に答える
15

C の根底にある最も重要なイデオロギーの 1 つは、開発者がサニティを提供するということであるため、サニティ チェックはありません。開発者が正気であると仮定すると、どこでも、ほぼ何でもできる言語になります。

これは明示的に述べられた目標ではありません — 誰かがこれをチェックする実装を思いつく可能性は十分にあります。多分彼らは持っています。しかし、C に慣れていた多くの人が C を使いたがるとは思えません。なぜなら、自分のコードがより一般的な実装に移植される可能性がある場合は、とにかくチェックを入れる必要があるからです。

于 2010-09-01T09:01:06.763 に答える
11

C言語全体は、「プログラマーが何をしているかを知っていれば、正しく動作します」というモットーで書かれています。プログラマーは、必要なすべてのチェックを行うことを知っている必要があります。NULL をチェックするだけでなく、destが を保持するのに十分な割り当てられたメモリを指してsrcいることを確認し、 の戻り値をチェックしfopenて、ファイルが実際正常に開かれたことを確認し、いつmemcpy安全でいつmemmove必要なのかを認識します。

NULLstrcpyをチェックしても、言語パラダイムは変わりません。それでもdest十分なスペースを指していることを確認する必要があります。これは、インターフェイスを変更しないと確認strcpy できないものです。srcまた、それが'\0'-terminated であることを確認する必要がありますが、これstrcpyもおそらくチェックできません。

NULL をチェックする C 標準ライブラリ関数がいくつかあります。たとえば、free(NULL)は常に安全です。しかし、一般に、C では、ユーザーが何をしているのかを知っていることを期待しています。

[C++ は一般的に<cstring>ライブラリを避け、std::string友人を支持します。]

于 2010-09-01T08:59:20.040 に答える
6
  1. 通常、ライブラリは、呼び出し元に失敗のセマンティクスをどのようにするかを決定させる方が適切です。strcpyどちらかの引数が である場合、あなたはどうしますNULLか? 黙って何もしない?失敗しassertますか (非デバッグ ビルドのオプションではありません)。

  2. オプトアウトするよりもオプトインする方が簡単です。strcpy入力を検証する独自のラッパーを作成し、代わりにそれを使用するのは簡単です。ただし、ライブラリ自体がこれを行った場合、 を再実装する以外に、これらのチェックを実行しないことを選択する方法はありませんstrcpy。(たとえば、渡す引数がstrcpyare ではないことを既に知ってNULLいるかもしれません。また、タイトなループで呼び出している場合や、電力使用量を最小限に抑えることを懸念している場合は、それが重要である可能性があります。) 一般に、それは優れています。より多くの自由を与える側で過ちを犯す (たとえその自由が追加の責任を伴うとしても)。

于 2010-09-01T10:45:44.953 に答える
3

最も可能性の高い理由は次のとおりです。が入力で動作strcpyするように指定されていないためですNULL(つまり、この場合の動作は未定義です)。

NULLでは、aが渡された場合、ライブラリの実装者は何を選択する必要があるでしょうか? 最善の方法は、アプリケーションをクラッシュさせることだと私は主張します。このように考えてみてください: クラッシュは、何かがうまくいかなかったという明らかな兆候です...NULL一方、黙って入力を無視すると、検出がはるかに困難なバグを隠す可能性があります。

于 2010-09-01T08:46:41.830 に答える
2

C の初期のターゲットは強力なメモリ保護をサポートしていたため、NULL チェックは実装されていませんでした。プロセスが NULL からの読み取りまたは NULL への書き込みを試行すると、メモリ コントローラーは CPU に範囲外のメモリ アクセスが試行されたこと (セグメンテーション違反) を通知し、カーネルは問題のあるプロセスを強制終了します。

NULL ポインタから読み書きしようとするコードは壊れているため、これは問題ありません。唯一の答えは、コードを書き直してmalloc(3)、友人からの戻り値をチェックし、是正措置を取ることです。割り当てられていないメモリへのポインターを使用しようとしているときには、状況を修正する方法について正しい決定を下すには遅すぎます。

于 2010-09-01T08:47:01.643 に答える
0

私によると、定義したい関数には事前条件と事後条件があります。前提条件を処理することは、関数の一部であってはなりません。以下は、man ページから取得した strcpy を使用するための前提条件です。

strcpy() 関数は、src が指す文字列 (終端の '\0' 文字を含む) を dest が指す配列にコピーします。文字列は重複してはならず、宛先文字列 dest はコピーを受け取るのに十分な大きさでなければなりません。

前提条件が満たされていない場合、物事は未定義になる可能性があります。

今、strcpy に NULL チェックを含めるかどうか。私はむしろ別の safe_strcpy を持ち、安全性を優先して、確実に NULL チェックを含め、オーバーフロー条件を処理します。それに応じて、私の前提条件が変更されます。

于 2010-09-01T09:13:48.587 に答える
0

C 標準ライブラリ関数は、アセンブリ コードの上にできる限り薄い追加の抽象化層であり、自分のものをドア越しに大量に取り出したくないものと考える必要があります。エラーチェックなど、それ以上のことはすべてあなたの責任です。

于 2010-09-01T09:05:31.760 に答える
0

それに対して定義されたエラーセマンティックはまったくありません。strcpy特に、 がエラー値を返す方法はありません。C99 は次のように述べています。

関数はのstrcpy値を返しますs1

したがって、適合する実装の場合、何かがうまくいかなかったという情報を返す可能性さえありません。では、なぜそれを気にするのですか。

strcpyほとんどのコンパイラは非常に効率的なアセンブラに直接置き換えられているため、これはすべて自発的なものだと思います。エラーチェックは呼び出し元次第です。

于 2010-09-01T11:18:42.080 に答える