c++ - 規定 - 定義されていない、指定されていない、実装定義の振る舞い




未 定義 未 規定 (6)

C ++標準n3337§1.3.10 実装定義の振る舞い

適切な形式のプログラム構造と正しいデータのために、実装に依存し、各実装ドキュメント

時々C ++標準はいくつかの構造に特定の動作を課すのではなく、特別な実装(ライブラリのバージョン)によって明確に定義された特定の動作を選択して記述する必要があると言います。 したがって、Standardがこれを記述していないにもかかわらず、ユーザーはプログラムがどのように動作するかを正確に知ることができます。

C ++標準n3337§1.3.24 未定義の動作

[注:この国際標準が動作の明示的定義を省略した場合、またはプログラムが誤った構造または誤ったデータを使用する場合、未定義の動作が予想される可能性があります。 許可された未定義の動作は、状況を完全に予測できない結果で完全に無視することから、環境の文書化された方法で(翻訳メッセージの発行の有無にかかわらず)翻訳またはプログラム実行中に動作すること、翻訳または実行を終了すること(発行診断メッセージの)。 多くの誤ったプログラム構成は未定義の動作を引き起こさない。 彼らは診断される必要があります。 - 終了ノート]

プログラムがC ++標準に従って定義されていない構造に遭遇したとき、それは何をしたいかを決めることができます(私に電子メールを送るか、電子メールをあなたに送るか、コードを完全に無視するかもしれません)。

C ++標準n3337§1.3.25 不特定の動作

適切に構成されたプログラム構造と正しいデータのために、実装に依存する[注:実装は、どのような動作が発生するかを記録する必要はありません。 可能な行動の範囲は、通常、この国際標準によって規定されている。 - 終了ノート]

C ++標準は、いくつかの構造に特定の振る舞いを課すのではなく、特定の実装(ライブラリのバージョン)によって明確に定義された振る舞いを選択する必要があるボットは必要ないと記載 )。 したがって、記述が提供されていない場合、プログラムがどのように振る舞うかをユーザが正確に知ることは難しいかもしれません。

CおよびC ++で定義されていない、指定されていない、および実装定義の動作の違いは何ですか?


未定義の振る舞いと未定義の振る舞いについて簡単に説明しています。

彼らの最終的な要約:

要約すると、不特定の動作は通常、あなたのソフトウェアが移植可能でなければならない限り、心配すべきではありません。 逆に、定義されていない動作は常に望ましくなく、決して発生しません。


いくつかのケースでは、有用で予測可能な方法で動作するはずのコンストラクトはたくさんありますが、実際にはすべての実装ですべてのケースでそうすることはできません。 しばしば、構築物が使用可能でなければならない一連のケースは、ターゲットプラットフォームおよびアプリケーションフィールドに依存する。 異なるターゲットとフィールドの実装は異なるケースのセットを処理する必要があるため、この標準では、どのケースが実装品質の問題として扱われるべきかという問題があります。 さらに、標準の作成者は、「適合する」実装が役に立たないほど品質が劣ることを禁じる必要がないことを見ているため、ゴミ以外の実装がサポートすることを期待した場合の動作を明示的に指示することはしばしばありません義務がなくても。

たとえば、コードは次のとおりです。

struct foo {int x;} = {0};
int main(void)
{
  foo.x = 1;
  return foo.x-1;
}

N1570 6.5p7には型のlvalue以外ではstruct foo型のオブジェクトにアクセスすることはできませんが、型struct fooオブジェクトの格納値にアクセスするには、型int [すなわちfoo.x ]の左辺値を使用しますstruct fooまたは文字型の左辺値でもなく、struct-member-access式を6.5p7の要件から除外する言語も含まれていません。

明らかに、単純なstruct-member-access式を扱うことができないコンパイラは、例外的に低い品質であるとみなされ、おそらく何かの多くには適していないはずです。 したがって、質の高い実施を目指す者は、規格がそれを義務づけているかどうかにかかわらず、そのような構成を支持することを期待することは妥当である。 コンパイラ作成者が意図した目的に適した高品質のコンパイラを作成するために誠実な努力を払うことができれば、コンパイラが適切かどうかの目的について公開されていれば、標準廃インク明らかにすべきことを述べようとする。 実用的で予測可能な振る舞いを持つべき多くのアクションは、実際には未定義の振る舞いである。なぜなら、標準の作者は、アクションが未定義の振る舞いを呼び出すという事実を使用するのではなく、 。


たぶん簡単な言葉遣いは、標準の厳密な定義より理解しやすいかもしれません。

実装定義の振る舞い
言語には、データ型があると言われています。 コンパイラのベンダーは、使用するサイズを指定し、それらが行ったことのドキュメントを提供します。

未定義の動作
あなたは何か間違っている。 たとえば、 intにはchar収まらない非常に大きな値があります。 あなたはその値をどのようにchar入れますか? 実際には方法はありません! 何かが起こる可能性がありますが、最も賢明なことは、そのintの最初のバイトをchar入れてしまうことです。 最初のバイトを割り当てるのは間違いですが、フードの中で何が起きるかは分かりません。

不特定の振る舞い
この2つの機能のうち、最初に実行される機能はどれですか?

void fun(int n, int m);

int fun1()
{
  cout << "fun1";
  return 1;
}
int fun2()
{
  cout << "fun2";
  return 2;
}
...
fun(fun1(), fun2()); // which one is executed first?

言語は左から右へ、または右から左への評価を指定しません! したがって、未定義の振る舞いは未定義の振る舞いを引き起こすかもしれませんが、あなたのプログラムは不特定の振る舞いを引き起こすべきではありません。

@eSKay私はあなたの質問は、より明確に答えを編集する価値があると思う:)

fun(fun1(), fun2());ためにfun(fun1(), fun2()); "実装定義"の動作ではありませんか? 結局のところ、コンパイラはどちらか一方のコースを選択する必要がありますか?

実装定義と未定義との違いは、コンパイラは最初のケースで動作を選択することになっていますが、2番目のケースでは動作する必要はありません。 たとえば、実装ではsizeof(int)定義が1つだけ必要です。 したがって、 sizeof(int)はプログラムのある部分では4で、他の部分では8であるとは言えません。 コンパイラがOKと言うことができる不特定の動作とは異なり、これらの引数を左から右に評価し、次の関数の引数は右から左に評価されます。 それは同じプログラムで起こる可能性があります。そのため、それが不特定と呼ばれています。 実際には、C ++は未定義の振舞いの一部が指定されていれば簡単に作成できました。 Stroustrup氏の答えをここで見てみましょう:

コンパイラにこの自由を与え、「通常の左から右への評価」を必要とするものとの違いは重要であると主張されている。 私は確信していますが、無限のコンパイラを自由に利用し、自由を積極的に擁護している人たちがいると、CやC ++世界の遠くの部分に浸透するには数十年かかるかもしれません。 私は+++++ ++のようなコードに対してすべてのコンパイラが警告するわけではないことに失望しています。 同様に、議論の評価の順序は不明である。

IMOはあまりにも多くの "もの"は未定義、未指定、実装定義などのままです。しかし、それは簡単に言えますし、例を挙げても修正するのは難しいです。 また、ほとんどの問題を回避して移植性の高いコードを生成することは、それほど難しいことではないことにも注意してください。


公式のCの根拠資料から

定義されてい ない振る舞い、 未定義の振る舞い、 実装 定義の振る舞いという用語は、Standardが持つ特性を完全に記述できない、または記述できないプログラムを作成する結果を分類するために使用されます。 この分類を採用する目的は、標準への準拠を取り除かずに、実装品質を市場における積極的な力とするとともに、一般的な拡張を可能にする実装間の特定の多様性を可能にすることである。 標準の附属書Fは、これら3つのカテゴリーのいずれかに該当する行動をカタログ化する。

不特定の振る舞いは、プログラムの翻訳において、実装者にある程度の自由度を与えます。 この緯度は、プログラムの翻訳に失敗していない限り拡大しません。

未定義の動作により、実装は、診断が困難な特定のプログラムエラーをキャッチしないようにライセンスを付与します。 可能な適合言語拡張の領域も識別する。実装者は、正式に定義されていない振る舞いの定義を提供することによって、言語を拡張することができる。

実装によって定義された動作は、実装者に適切なアプローチを選択する自由を与えますが、この選択をユーザに説明する必要があります。 実装定義で指定された動作は、一般に、ユーザが実装定義に基づいて意味のある符号化を行うことができる動作である。 実装の定義がどれくらい広範囲にあるべきかを決めるとき、実装者はこの基準に留意すべきである。 不特定の動作と同様、実装定義の振る舞いを含むソースの変換に失敗しただけでは適切な応答ではありません。


実装定義済み -

実装者は、文書化すべきであるが、標準は選択肢を与えるが、コンパイルすることを確かめる

不特定 -

実装定義されているが文書化されていない

未定義-

何かが起こるかもしれない、それを世話してください。





unspecified-behavior