C ++での不確定な動作と未定義の動作の違いは何ですか?この分類はCコードにも有効ですか?
3 に答える
以下の注釈は、C ++ではなくC標準、 ISO-9899に基づいていますが、意味は基本的に同じです(C標準のセクション3.4および4を参照してください。C++標準、 ISO-14882、セクション1.3も参照してください)。 ;後者のドキュメントでは、「不特定の値」をそのように定義していませんが、後でそのフレーズを明白な意味で使用しています)。公式の標準文書は無料ではありませんが(実際、高価です)、上記のリンクは委員会のページへのリンクであり、標準の無料の「ドラフト」が含まれています。これは、最終的な標準テキストと本質的に同等であると見なすことができます。
用語はあいまいさのはしごを表します。
だから、下に向かって....
ほとんどの場合、標準は特定の場合に何が起こるかを定義します。あなたがとを書いc=a+b
て、a
でb
ある場合int
、それc
はそれらの合計です(いくつかの詳細を法として)。もちろん、これが標準のポイントです。
実装定義の動作は、標準が特定の場合に発生することが許可されている2つ以上のことをリストしている場合です。どちらが優先されるかは規定されていませんが、実装(Cを解析する実際のコンパイラ)が選択肢を選択し、同じことを一貫して実行し、実装が選択を文書化する必要があります。たとえば、単一のファイルを複数のプロセスで開くことができるかどうかは、実装によって定義されます。
不特定の動作とは、標準にいくつかの選択肢がリストされている場合です。そのため、それぞれが標準に準拠していますが、それ以上は進みません。実装は、特定の場合に選択する選択肢の1つを選択する必要がありますが、毎回同じことを行う必要はなく、どの選択を行うかをドキュメントにコミットする必要もありません。たとえば、aのパディングビットstruct
は指定されていません。
未定義動作は最も極端なケースです。ここでは、すべての賭けがオフになっています。コンパイラまたはコンパイラが生成するプログラムが未定義の動作に遭遇した場合、コンパイラは何でも実行できます。メモリをスクランブルしたり、スタックやHCFを破損したり、極端な場合は悪魔を鼻から飛び出させたりする可能性があります。しかし、ほとんどの場合、クラッシュするだけです。そして、これらの動作はすべて標準に準拠しています。たとえば、変数が同じスコープ内で両方とも宣言されている場合、またはを記述static int i;
した場合、効果は未定義です。int i;
#include <'my file'.h>
'value'にも同様の定義があります。
不特定の値は有効な値ですが、標準ではそれが何であるかは示されていません。したがって、標準では、特定の関数が不特定の値を返すと言う場合があります。その値を保存して、必要に応じてエラーを発生させることなく確認できますが、それは何の意味もありません。関数は、月の満ち欠けに応じて、次回は異なる値を返す可能性があります。
実装定義の値は、実装定義の動作に似ています。不特定のように、それは有効な値ですが、実装のドキュメントは、返されるものについてそれ自体をコミットし、毎回同じことを行う必要があります。
不確定な値は、不特定よりもさらに不特定です。不特定の値またはトラップ表現のいずれかです。トラップ表現は標準です。魔法の値を表すと、何かに割り当てようとすると、未定義の動作になります。これは実際の値である必要はありません。おそらくそれについて考える最良の方法は、「Cに例外があった場合、トラップ表現は例外になる」ということです。たとえばint i;
、初期化せずにブロックで宣言した場合、変数の初期値i
は不確定になります、つまり、初期化する前にこれを他の何かに割り当てようとすると、動作は定義されておらず、コンパイラは前述の悪霊のトリックを試す権利があります。もちろん、ほとんどの場合、コンパイラーは、0やその他のランダムな有効な値に初期化するなど、それほど劇的で楽しいことはしませんが、何をしても、オブジェクトを受け取る資格はありません。
このすべての不正確さのポイントは、コンパイラの作成者に最大限の自由を与えることです。これはコンパイラーの作成者にとっては素晴らしいことですが(そして、Cコンパイラーをこのように膨大な範囲のプラットフォームで実行するのが合理的に簡単な理由の1つです)、貧しいユーザーにとっては楽しいというよりはむしろ面白いものになります。
編集1:不確定な値を明確にします。
編集2:C ++標準へのリンクを含めるため、委員会の草案は基本的に最終標準と同等ですが、無料であることに注意してください。
この規格では、未定義の動作と不確定な値について言及されていると思います。つまり、1つは動作に関するもので、もう1つは値に関するものです。
これらの2つはやや直交しています。たとえば、不確定な値が存在する場合でも、動作を明確に定義できます。
編集1: C11およびC ++ 11の最後のドラフトは、ここからオンラインで入手できます。最終的な標準のコピーがなく、それらがどのように見えるかがわからない場合は、C11ドラフトN1570およびC++11ドラフトn3242です。(テキストの外観に対するその他の調整と、いくつかの文言/文法の編集が行われました。)
編集2:「動作」のすべての出現を「動作」に修正して標準に一致させました。
C ++ 11およびC11標準を検索すると、不確定ルールまたは未定義ルールに一致するものはありません。不確定な値、不確定な順序付け、不確定な初期化されていないなどの用語があります。
Norman Grayの回答でトラップと例外の話が奇妙に思われる場合は、それらの用語がC11標準のセクション3の関連する定義を反映していることを知っておいてください。
C++はCの定義に依存しています。動作のタイプに関する多くの有用な定義は、C11のセクション3(C11)にあります。たとえば、不確定値は3.19.2で定義されています。C11のセクション2(規範的参照)は、追加の用語解釈のための他の情報源を提供し、セクション4は、標準に準拠していない結果として未定義動作などのケースが発生する場合を定義していることに注意してください。
C11のセクション3.4は動作を定義し、3.4.1は実装定義の動作を定義し、3.4.2はロケール固有の動作を定義し、3.4.3は未定義の動作を定義し、3.4.4は未指定の動作を定義します。値(セクション3.19)には、実装定義の値、不確定な値、および未指定の値があります。
大まかに言えば、不確定という用語は、それ自体では未定義の動作を引き起こさない、不特定/不明な状態を指します。たとえば、このC++コードには不確定な値が含まれます。{intx = x; }。(これは実際にはC ++ 11標準の例です。)ここでxは最初に整数として定義されていますが、その時点では明確に定義された値がありません。その後、任意の値(不確定/不明)に初期化されます。それが持っている価値!
よく知られている未定義動作という用語は、C11の3.4.3で定義されており、
この国際規格が要件を課していない、移植性のない、または誤ったプログラム構成または誤ったデータ
言い換えれば、未定義の動作は(ロジックまたは状態の)エラーであり、次に何が起こるかは不明です!したがって、次のような未定義の[動作]ルールを作成できます。C/ C ++コードを作成するときは、未定義の動作を避けてください。:-)
不確定な[動作]ルールは次のようになります。不確定なコードは、必要であり、プログラムの正確性や移植性に影響を与えない限り、記述しないでください。したがって、未定義の動作とは異なり、不確定な動作は必ずしもコード/データに誤りがあることを意味するわけではありませんが、その後の使用は誤りである場合とそうでない場合があります。したがって、プログラムの正当性が維持されるように注意する必要があります。
不確定に順序付けられているような他の用語は、本文にあります(たとえば、C11 5.1.2.3 para 3; C ++ 11、section 1.9 para。13;つまり、[intro.executation])。(ご想像のとおり、これは操作手順の不特定の順序を指します。)
IMOがこれらすべてのニュアンスに関心がある場合は、C++11とC11の両方の標準を取得する必要があります。これにより、定義などで必要とされる詳細レベルまで探索できます。このようなリンクがない場合は、最後に公開されたドラフトC11およびC++11標準で探索するのに役立ちます。