17

未定義の動作が呼び出されるたびにエラーを通知することを保証する C++ (および/または C) の実装は存在しますか? 明らかに、このような実装は標準の C++ 実装ほど効率的ではありませんが、デバッグ/テスト ツールとしては便利です。

そのような実装が存在しない場合、実装を不可能にする実際的な理由はありますか? それとも、誰もそれを実装する作業をまだ行っていないということですか?

編集:これをもう少し正確にするために:完了まで実行されたC++プログラムの特定の実行に対して、その実行のどの部分も未定義の動作を含まないというアサーションを作成できるコンパイラが必要です。

4

4 に答える 4

3

はいといいえ。

実用的な目的のために、実装によってC ++が安全な言語になる可能性があることはかなり確信しています。つまり、すべての操作が明確に定義された動作をします。もちろん、これには大きなオーバーヘッドが伴い、マルチスレッドコードの競合状態など、単純に実行不可能な場合もあります。

問題は、コードが他の実装で定義されていることを保証できないことです。つまり、UBを呼び出すことができます。たとえば、次のコードを確認してください。

int a;
int* b;

int foo() {
  a = 5;
  b = &a;
  return 0;
}

int bar() {
  *b = a;
  return 0;
}

int main() {
  std::cout << foo() << bar() << std::endl;
}

規格によれば、foobarが呼び出される順序は、実装によって決定されます。ここで、安全な実装では、この順序を定義する必要があり、おそらく左から右への評価になります。問題は、右から左に評価するとUBが呼び出されることです。これは、安全でない実装で実行するまでキャッチされません。安全な実装では、評価順序の各順列をコンパイルするか、静的分析を実行するだけで済みますが、これはすぐに実行不可能になり、決定不能になる可能性があります。

したがって、結論として、そのような実装が存在する場合、それはあなたに誤った安心感を与えるでしょう。

于 2012-12-28T18:00:47.743 に答える
2

新しいC規格には、新しいAnnexLに「分析可能性」という大まかなタイトルの興味深いリストがあります。それはいわゆるクリティカルUBであるUBについて話します。これには、とりわけ次のものが含まれます。

  • オブジェクトは、その存続期間外(6.2.4)に参照されます。
  • ポインタは、参照されている型と互換性のない型の関数を呼び出すために使用されます
  • プログラムは文字列リテラルを変更しようとします

これらはすべてUBであり、通常、コンパイル時に完全にテストできないため、キャプチャすることは不可能または非常に困難です。これは、有効なC(またはC ++)プログラムが、相互に多くを知らない可能性のある複数のコンパイル単位で構成されているためです。たとえば、あるプログラムが文字列リテラルへのポインタをパラメータを持つ関数に渡す場合char*、またはさらに悪いことに、const静的変数から-nessをキャストするプログラム。

于 2012-12-28T18:01:17.137 に答える
2

Two C interpreters that detect a large class of undefined behaviors for a large subset of sequential C are KCC and Frama-C's value analysis. They are both used to make sure that automatically generated, automatically reduced random C programs are appropriate to report bugs in C compilers.

From the webpage for KCC:

One of the main aims of this work is the ability to detect undefined programs (e.g., programs that read invalid memory).

A third interpreter for a dialect of C is CompCert's interpreter mode (a writeup). This one detects all behaviors that are undefined in the input language of the certified C compiler CompCert. The input language of CompCert is essentially C, but it renders defined some behaviors that are undefined in the standard (signed arithmetic overflow is defined as computing 2's complement results, for instance).

In truth, all three of the interpreters mentioned in this answer have had difficult choices to make in the name of pragmatism.

于 2012-12-28T18:42:36.450 に答える
-1

何かを「未定義の動作」として定義することの要点は、コンパイラでこの状況を検出する必要がないようにすることです。そのように定義されているため、さまざまなプラットフォームとアーキテクチャ用にコンパイラを構築でき、ハードウェアとソフトウェアに「未定義の動作を検出するためだけに」特定の機能を持たせる必要がありません。実際のメモリに書き込んでいるかどうかを検出できないメモリ サブシステムがあるとします。コンパイラまたはランタイム システムは、書き込んだことをどのように検出しますか?somepointer = rand(); *somepointer = 42;

いくつかの状況を検出できます。しかし、すべてが検出されることを要求すると、生活が非常に困難になります。

元の質問の編集を考えると、これをCで達成するのがもっともらしいとはまだ思いません.ほとんど何でも自由に行うことができます(ほとんど何でもへのポインタを作成し、これらのポインタは変換、インデックス付け、再計算、およびすべて他の方法)、あらゆる種類の未定義の動作を引き起こす可能性があります。ここに C のすべての未定義の動作のリストがあります- ファイルの最後の文字としてのバックスラッシュ (コンパイラ エラーを引き起こす可能性がありますが、1 つとして定義されていません) から「比較関数bsearch または qsort 関数によって呼び出されると、一貫性のない順序付け値が返されます。」

bsearch または qsort に渡された関数が一貫して値を並べ替えていることを確認するために、コンパイラをどのように作成しますか? もちろん、比較関数に渡されるデータが整数などの単純な型であればそれほど難しくはありませんが、データ型が複雑な型の場合は

struct {
    char name[20];
    char street[20];
    int age;
    char post_code[10];
};

プログラマーは、名前の昇順、通りの昇順、年齢の降順、郵便番号の昇順に基づいてデータを並べ替えることにしましたか? それがあなたが望むものであるが、どういうわけかコードが台無しになり、ポストコード比較が一貫性のない結果を返す場合、事態はうまくいかないでしょうが、そのケースを正式に検査することは非常に困難です. 同様に曖昧で複雑なものは他にもたくさんあります。確かに、あなたのコードは名前や住所などをソートしないかもしれませんが、おそらく誰かがいつかそのようなものを書くでしょう。

于 2012-12-28T17:37:00.843 に答える