「IB」と「UB」は正確にはどういう意味ですか?


110

特に「C ++」のコンテキストで、「IB」および「UB」という用語が何度も使用されているのを見てきました。私はそれらをグーグルで試しましたが、どうやらこれらの2文字の組み合わせには多くの用途があります。:P

だから、私はあなたに尋ねます...彼らが悪いことであるかのように言われるとき、彼らはどういう意味ですか?


5
他の人の編集をロールバックする場合は、スペル、句読点、文法が完全であることを確認してください。元のテキストを大幅に改善した編集をロールバックしても意味がありません。
Robert Harvey

回答:


139

IB:実装定義の動作。標準では、正確な動作を定義するために特定のコンパイラ/プラットフォームに任せていますが、定義する必要があります。

実装定義の動作を使用すると便利ですが、コードの移植性が低下します。

UB:未定義の動作。標準では、未定義の動作を呼び出すプログラムの動作を指定していません。理論的には悪魔が鼻から飛び出す可能性があるため、「鼻の悪魔」とも呼ばれます。

未定義の動作を使用することは、ほとんど常に悪い考えです。動作するように見える場合でも、環境、コンパイラ、またはプラットフォームに変更を加えると、コードがランダムに破損する可能性があります。


11
C ++で未定義の動作を使用しているため、私はまだ誰かの鼻から飛び出す悪魔を待っています。最初のコンパイラが新しいC ++標準に完全に準拠すると、それが起こると思います。
OregonGhost

4
@OregonGhost:私はあなたが正しいと思います。私はそれがユニコーンで数回起こるのを見ましたが、悪魔は決してありません。
トーマス

33
@OregonGhost-悪魔が持つべきホーンの数は標準で規定されていません。
DVK 2010年

5
@Michael Burr:私は「キャッチファイア」を好む。それは明らかに壊滅的であり、少なくとも漠然とした妥当性の空気があります(このスレッドを読んでいるシステムの場合、ソフトウェアの障害ではなくハードウェアの理由で、コンピューターのハードウェアが時々発火することがあります)。
スティーブジェソップ

1
この質問に誰も回答していないというのはおかしいです。

19

実装定義の動作と未定義の動作

C ++標準は、さまざまな構成の影響について非常に具体的であり、特に、以下のカテゴリの問題に常に注意する必要があります。

  • 未定義の動作とは、保証がまったくないことを意味します。コードが機能するか、ハードドライブに火をつけたり、悪魔に鼻を飛ばしたりできます。C ++言語に関する限り、絶対に何かが起こる可能性があります。実際には、これは通常、回復不可能なバグがあることを意味します。これが発生した場合、アプリケーションについて何も信頼することはできません(この未定義の動作の影響の1つは、アプリの他の部分で使用されているメモリを台無しにするためであったためです)。一貫性を保つ必要はないため、プログラムを2回実行すると結果が異なる場合があります。それは月の満ち欠け、着ているシャツの色、その他すべてに依存します。

  • 未指定の動作とは、プログラムが正常で一貫した処理を行う必要があることを意味しますが、これを文書化する必要はありません。

  • 実装定義の動作は未指定に似ていますが、コンパイラの作成者も文書化する必要があります。この例は、の結果ですreinterpret_cast通常、これはアドレスを変更せずにポインタのタイプを変更するだけですが、マッピングは実際には実装定義であるため、コンパイラこの選択を文書化している限り、コンパイラ完全に異なるアドレスにマップできます。別の例は、intのサイズです。C ++標準では、2、4、8バイトのいずれでも問題ありませんが、コンパイラーによって文書化されている必要あります。

しかし、これらすべてに共通するのは、回避するのが最もよいということです。可能な場合は、C ++標準自体で100%指定されている動作を使用してください。これにより、移植性が保証されます。

多くの場合、実装によって定義された動作にも依存する必要があります。それは避けられないかもしれませんが、それでも注意を払い、異なるコンパイラ間で変更される可能性のあるものに依存していることに注意してください。

一方、未定義の動作は常に回避する必要があります。一般に、プログラムが何らかの方法で爆発することを前提とする必要があります。


1
移植性を気にする場合 UBを使用しないでください。特定の実装は、特定の未定義の動作に対して何が起こるかを定義でき、場合によっては(特にデバイスドライバーや小さな組み込みシステム)、それらを使用する必要があります。
ジェリーコフィン

3
@ジェリー:いいえ、完全に未定義の UBは避けてください。platform / implementation / runtime / compilerがさらに保証を提供する場合、動作に依存して移植性を失う可能性があります。しかし、それからそれはもはや未定義ではありません...ほとんどの場合、しかし、あなたはそのような保証はなく、未定義は単に未定義であり、すべてのコストで避けられるべきです。
2010年

「一貫性」は、不特定の動作の誤解を招く説明である可能性があります。これは、操作の一般的なコンテキストと一致している必要あります。たとえば、式に「指定されていない値」がある場合、結果は値である必要あり、それを格納する場合、格納されている値はその後それ自体と等しいと比較する必要があります。しかし、不特定の結果は、時間をかけて一貫している必要はありません(もう一度実行した場合、同じ入力に対して同じ出力)、または確定的でさえあります。
Steve Jessop、

「もはやまったく未定義ではない」-これは、標準まったく未定義であり、UBは、標準では未定義の省略形です。あなたの例では、それは実装によって定義されています。さらに言えば、オブジェクトコードをチェックして、二度と再コンパイルする予定がない場合は、標準または実装で定義されていない動作に依存する可能性があります;-)
Steve Jessop

「その後、それ自体と等しいものと比較しなければならない」。うーん、NaNでない限り。とにかく、それはそのタイプに必要なあらゆる振る舞いを持たなければなりません。
Steve Jessop、

8
  • IB:実装で定義された動作です-コンパイラーはその動作を文書化する必要があります。>>負の値に対して演算を実行することは一例です。

  • UB:未定義の動作-コンパイラは、単にクラッシュしたり、予期しない結果を与えたりするなど、これまでに何でもできます。nullポインターの逆参照はこのカテゴリに分類されますが、配列オブジェクトの境界外にあるポインター算術などの微妙なことも含まれます。

別の関連用語は「不特定の動作」です。これは、実装で定義された動作と未定義の動作の間の一種です。不特定の動作の場合、コンパイラーは標準に従って何かを行う必要がありますが、標準が与える選択はコンパイラー次第であり、定義する必要はありません(または一貫性さえ必要ありません)。副次式の評価順序のようなものはこのカテゴリーに分類されます。コンパイラーは、これらを好きな順序で実行できます。また、ビルドによって、または同じビルドの実行ごとに異なる方法で実行できます(可能性は低いですが、許可されています)。


4

ショートバージョン:

実装定義の動作(IB):正しくプログラムされているが不確定*

未定義の動作(UB):正しくプログラムされていない(つまり、バグ!)

*)言語標準に関する限り、「不確定」です。もちろん、固定プラットフォームでは確定です。


アクションが実装定義の動作を呼び出すことを標準が示している場合、実装は、そのアクションから生じる一貫した動作を指定する必要があります。残念ながら、起こり得る結果を特定するために実装が必要となる動作のカテゴリはありませんが、特定の結果を一貫して発生させる必要はありません。
スーパーキャット2015

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.