5

私の読書から理解しているように、 undefined-behavior は、コンパイル時にいくつかの同一でない代替手段をコンパイラに残した結果です。ただし、厳密なコーディング慣行に従う場合 (各代入と各等号を別々のステートメントに入れる、適切なデバッグとコメントを付けるなど)、未定義のソースを見つける際に重大な問題を引き起こすべきではないということではないでしょうか? -行動。

さらに、発生するエラーごとに、コードを特定すると、その特定のステートメントの代わりにどのステートメントを使用できるかを知る必要がありますね。

編集: 書くつもりのないコードを書いた場所には興味がありません。私は、数学的論理によって正しいコードが機能しない例に興味があります。

また、「優れたコーディング プラクティス」とは、数行ごとの強力な有益なコメント、適切なインデント、および定期的なデバッグ ダンプであると考えています。

4

4 に答える 4

10

未定義の動作は、必ずしもコンパイラに複数の選択肢を残すわけではありません。最も一般的なのは、意味のないことをしているだけです。

たとえば、次のコードを見てください。

int arr[2];
arr[200] = 42;

これは未定義の動作です。コンパイラに複数の選択肢が与えられたわけではありません。私がやっていることは意味をなさないというだけです。理想的には、そもそも許可されるべきではありませんが、コストがかかる可能性のある実行時チェックがなければ、このようなことがコードで発生しないことを保証できません。そのため、C++ では、規則に固執するプログラムの動作のみを言語が指定するという単純な規則になります。上記の例のようにエラーが発生した場合、何が起こるかは未定義です。

ここで、このエラーをどのように検出するかを想像してください。どうやって表面化するの?問題が発生することは決してないように思われるかもしれません。おそらく、たまたまプロセスにマップされているメモリに書き込み (アクセス違反が発生しないようにするため)、それ以外の方法で使用されることはありません (プログラムの他の部分がガベージ値を読み取ったり、書き込んだものを上書きしたりすることはありません)。 )。その後、プログラムにバグがなく、問題なく動作しているように見えます。

または、プロセスにマップされていないアドレスにヒットする可能性もあります。その後、プログラムはすぐにクラッシュします。

または、プロセスにマップされているアドレスにヒットする可能性がありますが、後で何かに使用されます。わかっているのは、遅かれ早かれ、そのアドレスから読み取る関数が予期しない値を取得し、奇妙な動作をするということだけです。その部分はデバッガーで簡単に見つけることができますが、そのガベージ値がいつどこから書き込まれについては何もわかりません。そのため、エラーの原因を突き止める簡単な方法はありません。

于 2010-01-12T05:58:44.717 に答える
7

まず、C ++03標準からのいくつかの定義:

1.3.5実装定義の動作

実装に依存し、各実装が文書化する、整形式のプログラム構成と正しいデータの動作

1.3.12未定義動作

この国際規格が要件を課していない、誤ったプログラム構成または誤ったデータの使用時に発生する可能性があるような動作。この国際規格で明示的な定義または動作の説明が省略されている場合も、未定義の動作が予想される場合があります。

1.3.13不特定の動作

実装に依存する、整形式のプログラム構成と正しいデータの動作。どの動作が発生するかを文書化するために実装は必要ありません。

不特定の振る舞いはUBと呼ばれる可能性がありますが、私はそれを見たことがありません。UBは常に未定義の振る舞いを意味します。 標準全体を通して、「Xを実行することは未定義の動作です」と同様のステートメントがありますが、単にカバーされていないケースに遭遇することがあります。

別の言い方をすれば、どこかに未定義の動作がある場合、すべての賭けはオフになります。標準に関する限り、あなたのプログラムは、スーパーボウルの週末に義母を招待することから、nethackを実行することまで、何でもすることができます。UBの性質上、テストすることはできず、コンパイラーからの支援を期待することもできません。(いくつかの些細なことですが、一般的なエラーコンパイラは一般的に診断を生成します。)

通常、何かがUBとして定義されるのは、論理的に意味がないため(たとえば、範囲外の配列にアクセスする場合)ですが、多くの場合、実行時に実装で防止するために多くの作業を行う必要があるためです。C ++はCから派生していることを忘れないでください。高度に最適化されたプログラムを作成できることは、両方の言語の主要な目標です。この目的のために、言語はプログラマーに任せて、「使用しないものに対してお金を払わない」という原則に関連して、これらの状況でコードが正しいことを確認します。

つまり、最後に、UBは悪い、非常に悪いです。絶対に避けてください。ただし、UBの難しい部分は、それが何であるか、またはどのような状況で発生するかを認識していません。難しいのは、UBを呼び出すときに認識することです。例えば:

std::string s = "abc";
char& c = s[0];
cout.write(s.data(), s.length());
c = '-';

完全に合理的に見えますよね?いいえ、これはUBですが、一般的なすべての実装で期待どおりに機能します。

于 2010-01-12T06:38:00.270 に答える
1

「未定義の動作」の正式な定義があるかどうかはわかりませんが、適切なコーディング標準に従うことであいまいさが減り、コンパイルや実行時の問題が少なくなる可能性があります。

ただし、2 人のプログラマーに「優れたコーディング標準」について合意してもらうことは、複雑でエラーが発生しやすいプロセスです。

2 番目の質問に対して、はい、コンパイラは通常、問題を解決するために使用できるエラー コードを出力します。

于 2010-01-12T05:58:41.770 に答える
1

私の読書から理解しているように、 undefined-behavior は、コンパイル時にいくつかの同一でない代替手段をコンパイラに残した結果です。

それは未定義の動作の原因の1 つかもしれませんが、あまりにも抽象的に話しています。「コンパイル時に同一ではない代替手段」が意味する具体的な例が必要です。

「厳密なコーディング プラクティスに従う」とは、未定義の動作を引き起こすロジックを使用しないことを意味する場合、そうです (未定義の動作がないため)。未定義の動作によるバグの追跡は、論理エラーによるバグの追跡よりも簡単かもしれませんし、そうでないかもしれません。

「未定義の動作」をもたらすコードは、依然として正当な C++ コードであることに注意してください。特定の実装を備えた特定のプラットフォーム上の特定のプログラムで「未定義の動作」が予測可能である場合、それはほとんど使用されるべきではないコード/ロジックのクラスであると考えています。言語が「未定義の動作」と見なすものが、実際には特定の環境/一連の制約に対して定義される場合があります。

于 2010-01-12T06:01:37.193 に答える