CおよびC ++の未定義の動作とは何ですか?不特定の動作と実装定義の動作はどうですか?それらの違いは何ですか?
未定義の振る舞いは、他の言語から来たプログラマーにとって驚くべきCおよびC ++言語の側面の1つです(他の言語はそれをよりよく隠そうとします)。基本的に、多くのC ++コンパイラがプログラムのエラーを報告しない場合でも、予測可能な方法で動作しないC ++プログラムを作成することは可能です。
古典的な例を見てみましょう:
#include <iostream>
int main()
{
char* p = "hello!\n"; // yes I know, deprecated conversion
p[0] = 'y';
p[5] = 'w';
std::cout << p;
}
変数p
は文字列リテラルを指し、"hello!\n"
以下の2つの割り当てはその文字列リテラルを変更しようとします。このプログラムは何をしますか?C ++標準のセクション2.14.5パラグラフ11によると、未定義の動作を呼び出します。
文字列リテラルを変更しようとした場合の影響は定義されていません。
「しかし、待ってください。これを問題なくコンパイルして出力を取得できますyellow
」または「未定義の文字列リテラルは読み取り専用メモリに格納されているため、最初の割り当て試行でコアダンプが発生します」と叫ぶ人がいます。これはまさに未定義の振る舞いの問題です。基本的に、この標準では、未定義の振る舞い(鼻の悪魔でさえ)を呼び出すと、何でも起こります。言語のメンタルモデルによると「正しい」行動がある場合、そのモデルは単に間違っています。C ++標準には、唯一の投票期間があります。
未定義の動作の他の例には、境界を超えた配列へのアクセス、nullポインターの逆参照、存続期間が終了した後のオブジェクトへのアクセス、またはのような巧妙な式の記述が含まれi++ + ++i
ます。
C ++標準のセクション1.9では、未定義の振る舞いの危険性の低い2つの兄弟、未定義の振る舞いと実装定義の振る舞いについても言及しています。
この国際規格のセマンティック記述は、パラメータ化された非決定論的抽象マシンを定義します。
抽象マシンの特定の側面と操作は、この国際規格で実装定義として説明されています(たとえば
sizeof(int)
)。これらは、抽象マシンのパラメーターを構成します。各実装には、これらの点での特性と動作を説明するドキュメントを含める必要があります。抽象マシンの他の特定の側面と操作は、この国際規格では指定されていないものとして説明されています(たとえば、関数への引数の評価の順序)。可能な場合、この国際規格は一連の許容可能な動作を定義します。これらは、抽象マシンの非決定論的側面を定義します。
他の特定の操作は、この国際規格では未定義として説明されています(たとえば、nullポインターの逆参照の影響)。[注:この国際規格は、未定義の動作を含むプログラムの動作に要件を課していません。—エンドノート]
具体的には、セクション1.3.24には次のように記載されています。
許容される未定義の動作は、予測できない結果で状況を完全に無視することから、環境に特徴的な文書化された方法で翻訳またはプログラムの実行中に動作すること(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(発行あり)にまで及びます。診断メッセージの)。
未定義の動作に遭遇するのを避けるために何ができますか?基本的に、あなたは彼らが何について話しているかを知っている著者による良いC ++の本を読まなければなりません。インターネットチュートリアルをねじ込みます。ブルシルトをねじ込みます。
さて、これは基本的に標準からのストレートコピーペーストです
3.4.1 1実装定義の動作不特定の動作。各実装は、選択がどのように行われるかを文書化します。
2例実装定義の動作の例は、符号付き整数が右にシフトされたときの上位ビットの伝搬です。
3.4.3 1移植不可能または誤ったプログラム構成、または誤ったデータを使用した場合の未定義の動作動作。この国際規格は要件を課していません。
2注考えられる未定義の動作は、予測できない結果で状況を完全に無視することから、環境に特徴的な文書化された方法で翻訳またはプログラムの実行中に動作すること(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(診断メッセージの発行)。
3例未定義の動作の例は、整数オーバーフローの動作です。
3.4.4 1不特定の動作不特定の値の使用、またはこの国際規格が2つ以上の可能性を提供し、どのような場合でも選択される要件を課さないその他の動作
2例不特定の動作の例は、関数への引数が評価される順序です。
おそらく、簡単な言い回しは、標準の厳密な定義よりも理解しやすいかもしれません。
実装定義の動作
この言語では、データ型があると言われています。コンパイラベンダーは、使用するサイズを指定し、実行した内容のドキュメントを提供します。
未定義の振る舞い
あなたは何か間違ったことをしています。たとえば、に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());
動作は「実装が定義されている」のではないのですか?結局のところ、コンパイラはどちらかのコースを選択する必要がありますか?
実装定義と未指定の違いは、コンパイラーが最初のケースで動作を選択することになっているが、2番目のケースでは選択する必要がないことです。たとえば、実装には、の定義が1つだけ必要ですsizeof(int)
。したがって、sizeof(int)
プログラムの一部で4、他の部分で8であるとは言えません。コンパイラがOKと言うことができる不特定の動作とは異なり、これらの引数を左から右に評価し、次の関数の引数を右から左に評価します。同じプログラムで発生する可能性があるため、unspecifiedと呼ばれます。実際、指定されていない動作のいくつかが指定されていれば、C ++はより簡単になりました。そのためのStroustrup博士の答えをここで見てください:
コンパイラにこの自由を与えることと「通常の左から右への評価」を要求することとの間の違いは重要である可能性があると主張されています。私は確信が持てませんが、自由を利用する無数のコンパイラーとその自由を熱心に擁護する人々がいると、変更は難しく、CおよびC ++の世界の遠い隅に浸透するのに数十年かかる可能性があります。すべてのコンパイラが++ i + i ++などのコードに対して警告するわけではないことに失望しています。同様に、引数の評価の順序は指定されていません。
IMOの「もの」が多すぎて、未定義、未指定、実装定義などが残されています。ただし、これは簡単に言うことができ、例を示すこともできますが、修正するのは困難です。また、ほとんどの問題を回避して移植可能なコードを作成することはそれほど難しいことではないことにも注意してください。
公式のC根拠文書から
未指定の動作、未定義の動作、および実装定義の動作という用語は、標準で完全に記述されていない、または完全に記述できないプロパティを持つプログラムを作成した結果を分類するために使用されます。この分類を採用する目的は、標準への適合性のキャッシュを削除することなく、実装の品質を市場で積極的に発揮できるようにするだけでなく、特定の人気のある拡張機能を可能にする実装間の特定の多様性を可能にすることです。標準の付録Fは、これら3つのカテゴリのいずれかに分類される動作をカタログ化しています。
不特定の動作は、実装者にプログラムの翻訳にある程度の自由度を与えます。この許容範囲は、プログラムの翻訳に失敗するまでは拡張されません。
未定義の動作は、診断が難しい特定のプログラムエラーをキャッチしないように実装者にライセンスを与えます。また、準拠する可能性のある言語拡張の領域を識別します。実装者は、公式に定義されていない動作の定義を提供することにより、言語を拡張できます。
実装定義の動作により、実装者は適切なアプローチを自由に選択できますが、この選択についてユーザーに説明する必要があります。実装定義として指定された動作は、一般に、ユーザーが実装定義に基づいて意味のあるコーディング決定を行うことができる動作です。実装者は、実装定義をどの程度広範にするかを決定する際に、この基準を念頭に置く必要があります。不特定の動作と同様に、実装で定義された動作を含むソースの変換に失敗するだけでは、適切な対応にはなりません。
未定義の振る舞いと不特定の振る舞いについては、簡単に説明しています。
彼らの最終的な要約:
要約すると、不特定の動作は、ソフトウェアがポータブルである必要がない限り、通常は心配する必要はありません。逆に、未定義の動作は常に望ましくなく、発生してはなりません。
歴史的に、実装定義の動作と未定義の動作はどちらも、標準の作成者が、品質の実装を作成する人々が判断を使用して、で実行されている目的のアプリケーションフィールドのプログラムに役立つ動作保証がある場合はそれを決定することを期待する状況を表しています。意図されたターゲット。ハイエンドの数値計算コードのニーズは、ローレベルのシステムコードのニーズとはまったく異なり、UBとIDBの両方により、コンパイラの作成者はこれらのさまざまなニーズに柔軟に対応できます。どちらのカテゴリーも、実装が特定の目的に、あるいはあらゆる目的にさえ役立つ方法で動作することを義務付けていません。ただし、特定の目的に適していると主張する品質の実装は、規格で要求されているかどうかに関係なく、そのような目的に適した方法で動作する必要があります。
実装定義の動作と未定義の動作の唯一の違いは、前者では、実装で何もできない場合でも、実装が一貫した動作を定義して文書化する必要があることです。それらの間の境界線は、実装が動作を定義するのに一般的に役立つかどうかではなく(コンパイラの作成者は、標準で要求されているかどうかに関係なく、実用的な場合に有用な動作を定義する必要があります)、動作の定義が同時にコストがかかる実装があるかどうかです。と役に立たない。そのような実装が存在する可能性があるという判断は、他のプラットフォームで定義された動作をサポートすることの有用性についての判断を意味するものではありません。
残念ながら、1990年代半ば以降、コンパイラの作成者は、動作の義務がないことを、動作の保証が不可欠なアプリケーション分野でも、実質的にコストがかからないシステムでも、コストに見合わないという判断として解釈し始めています。UBを合理的な判断を行使するための招待として扱う代わりに、コンパイラの作成者はUBをそうしない言い訳として扱い始めました。
たとえば、次のコードがあるとします。
int scaled_velocity(int v, unsigned char pow)
{
if (v > 250)
v = 250;
if (v < -250)
v = -250;
return v << pow;
}
2の補数の実装では、正か負v << pow
かv
に関係なく、式を2の補数シフトとして扱うために労力を費やす必要はありません。
しかし、今日のコンパイラ作成者の間で好まれる哲学v
は、プログラムが未定義の振る舞いを行う場合にのみ負になる可能性があるため、プログラムにの負の範囲をクリップさせる理由はないことを示唆していますv
。負の値の左シフトは、重要なすべてのコンパイラでサポートされていましたが、既存のコードの多くはその動作に依存していますが、現代の哲学では、標準では左シフトの負の値はUBであると解釈されます。コンパイラの作成者はそれを無視してかまいません。
実装の定義-
実装者は、十分に文書化されている必要があり、標準は選択肢を提供しますが、必ずコンパイルすることを望んでいます
詳細不明-
実装定義と同じですが、文書化されていません
未定義-
何かが起こるかもしれません、それの世話をしてください。
C ++標準n3337 § 1.3.10処理系定義の動作
実装に依存し、各実装が文書化する、整形式のプログラム構成と正しいデータの動作
C ++標準は、一部の構成に特定の動作を課さない場合がありますが、代わりに、特定の実装(ライブラリのバージョン)によって特定の明確に定義された動作を選択して記述する必要があると述べています。そのため、Standardで説明されていなくても、ユーザーはプログラムがどのように動作するかを正確に知ることができます。
C ++標準n3337 § 1.3.24未定義の動作
この国際規格が要件を課していない動作[注:この国際規格が動作の明示的な定義を省略している場合、またはプログラムが誤った構成または誤ったデータを使用している場合、未定義の動作が予想される場合があります。許容される未定義の動作は、予測できない結果で状況を完全に無視することから、環境に特徴的な文書化された方法で翻訳またはプログラムの実行中に動作すること(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(発行あり)にまで及びます。診断メッセージの)。多くの誤ったプログラム構成は、未定義の動作を引き起こしません。それらは診断される必要があります。—エンドノート]
プログラムがC ++標準に従って定義されていない構成に遭遇すると、やりたいことを何でも実行できます(おそらく、私に電子メールを送信するか、あなたに電子メールを送信するか、コードを完全に無視します)。
C ++標準n3337 § 1.3.25 、不特定の行動
実装に依存する、整形式のプログラム構成と正しいデータの動作[注:実装は、発生する動作を文書化する必要はありません。可能な動作の範囲は、通常、この国際規格によって示されます。—エンドノート]
C ++標準は、一部の構造に特定の動作を課しませんが、代わりに、特定の実装(ライブラリのバージョン)によって特定の明確に定義された動作を選択する必要があると述べています(ボットは説明する必要はありません)。したがって、説明が提供されていない場合、ユーザーはプログラムがどのように動作するかを正確に知ることが難しい場合があります。
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
ランボルギーニの創設者であるフェルッチオランボルギーニが100歳になるのは毎日ではありません(そうです、彼は死んでいて、まだ死んでいると思います。
Appleが自動車分野に参入するという噂はかなり前から渦巻いており、AppleウォッチャーがSixtyEight Researchという会社がAppleの自動車研究開発のシェル会社である可能性が高いと判断したとき、その渦巻きは本当に渦巻いた。また、会社が購入した車は1台だけであることが知られており、その車はAppleが何を考えているかについての手がかりでいっぱいになる可能性があることも伝えています。
太陽系の外側にある架空の大きな物体である惑星Xの探索は、何十年にもわたって人間を魅了してきました。その検索の最新の章は、地球の10倍の大きさで、公転周期が15であるほど遠くにある惑星を指しています。
カムニュートンは昨日、簡単な265ヤードと3回のタッチダウンでファルコンズを引き裂き、別の素晴らしいゲームをしました。その日のハイライトは、上のタッチダウンスローでした。これは、視聴するたびにばかげているだけです。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。