CまたはC++で未定義の動作を呼び出すと、何でも起こり得るという警告を聞いたことがあるでしょう。
これは実行時の動作に限定されますか、それともコンパイル時の動作も含まれますか?特に、コンパイラーは、未定義の動作を呼び出す構造に遭遇すると、コードを拒否することを許可されますか(そうするための標準に他の要件がない場合)、またはクラッシュすることさえできますか?
CまたはC++で未定義の動作を呼び出すと、何でも起こり得るという警告を聞いたことがあるでしょう。
これは実行時の動作に限定されますか、それともコンパイル時の動作も含まれますか?特に、コンパイラーは、未定義の動作を呼び出す構造に遭遇すると、コードを拒否することを許可されますか(そうするための標準に他の要件がない場合)、またはクラッシュすることさえできますか?
「あなたはすべて実際の定義を無視し、メモに焦点を合わせています。標準は要件を課していません。」-@ R.MartinhoFernandes
上記のメッセージは、Lounge <C ++>の特定のユーザーによって作成されたものであり、非常に有効な議論をしています。未定義動作を呼び出すコードに関しては、標準は要件を課していません。
未定義動作は、 C ++ 11とC99の両方の標準からの以下の引用で検証されているように、コンパイラによる入力データ(つまりコード)の解析の隅々まで広がっています。
一文であなたの質問に答えるために;
「環境に特徴的な文書化された方法で」は一種の奇妙なステートメントです。特定のコード(無効)でクラッシュする可能性があることを文書化したコンパイラを記述して、必要なときにクラッシュする可能性を与えることができます。
1. C ++ 11/C99標準からの引用
### c ++ 11
### 1.3.24 [defns.undefined]
未定義動作; この国際規格が要件を課していない動作
[注:
この国際規格が動作の明示的な定義を省略している場合、またはプログラムが誤った構成または誤ったデータを使用している場合、未定義の動作が予想される場合があります。
許容される未定義の動作は、予測できない結果を伴う状況を完全に無視することから、環境に特徴的な文書化された方法での翻訳 またはプログラム実行中の動作(診断メッセージの発行の有無にかかわらず)、 翻訳または実行の終了(発行あり)にまで及びます。診断メッセージの)。
多くの誤ったプログラム構成は、未定義の動作を引き起こしません。それらは診断される必要があります。
—エンドノート]
### c99
3.4.3-未定義動作
移植性のない、または誤ったプログラム構成または誤ったデータの使用時の動作。この国際規格は要件を課していません。
注考えられる未定義の動作は、予測できない結果を伴う状況を完全に無視することから、環境に特徴的な文書化された方法での翻訳またはプログラムの実行中の動作(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(診断メッセージの発行)。
動作が定義されていない場合、コンパイラはそれを受け入れ、拒否し、警告を発し、標準に従って、クラッシュ、ハング、またはコンピュータにウイルスをインストールする可能性があります。
実際には、コンパイラを作成している場合、意図的にこれらのことを行う必要があるという意味ではありませんが、たとえば、パフォーマンス上の利点が正当化される場合は、定義されたケースで機能し、未定義のケースでクラッシュまたはハングするアルゴリズムを使用できます。 。
それでも、評判の良いコンパイラはそれを回避するか、少なくともそれを非常によく文書化しています。
実行時の動作に限定されません。ISO / IEC 14882、初版、1998-09-01、1.3.12によると、注記(非規範的):「許容される未定義の動作は、...から、文書化された方法での翻訳またはプログラミングの実行中の動作にまで及びます。環境の」。言い換えると、標準では、実装は、文書化されていれば、オペレーティングシステム(または他の環境)が許可するすべてのことを実行できるとしています。
私は常に標準の引用符が大好きなので、それがあなたが探しているものである場合、標準は未定義の動作を次のように定義します
この国際規格が要件を課していない動作
[注:この国際規格で、プログラムが誤った構成または誤ったデータを使用する場合の動作の明示的な定義が省略されている場合、未定義の動作が予想される場合があります。許容される未定義の動作は、予測できない結果を伴う状況を完全に無視することから、環境に特徴的な文書化された方法での翻訳またはプログラムの実行中の動作(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(発行あり)にまで及びます。診断メッセージの)。多くの誤ったプログラム構成は、未定義の動作を引き起こしません。それらは診断される必要があります。—エンドノート]
そして、「翻訳」は基本的にソースから最終製品(アセンブリなど)に行きます。したがって、これら2つの可能性を組み合わせて、
翻訳中に予測できない結果を伴う状況を完全に無視する
そうです、コンパイラはコンパイル中および実行時に未定義の動作を自由に示すことができます。
未定義動作の少なくともいくつかの形式は、コンパイルの行為自体が標準の管轄外の方法で動作する原因となる可能性があります。たとえば、規格の作成者は、次のようなものの使用を排除したくありませんでした。
#include `someProg arg`
また
#pragma exec-include "someProg arg"
与えられた引数で実行someProg
し、そのようなプログラムの出力をソーステキストの一部であるかのように扱う手段として。このような構文によって呼び出されるプログラムの動作は標準の管轄外であるため、このような構造は、標準の観点からは、コンパイル時にUBを呼び出すと単純に見なされます。