10

未定義の動作は潜在的に何かを引き起こす可能性があり、UBを含むプログラムは潜在的に無意味になることを私は知っています。未定義の動作が問題を引き起こす可能性があるプログラムの最も早いポイントを特定する方法があるかどうか疑問に思いました。これが私の質問を説明するための例です。

void causeUndefinedBehavior()
{
   //any code that causes undefined behavior
   //every time it is run
   char* a = nullptr;
   *a;
}


int main()
{
 //code before call
 //...
 causeUndefinedBehavior();
 //code after call
 //...
}

私の理解では、未定義の動作が引き起こされる可能性のある時間(必ずしも明示されているとは限りません)は次のとおりです。

  1. いつcauseUndefinedBehavior()コンパイルされますか。
  2. いつmain()コンパイルされますか。
  3. プログラムの実行時。
  4. その時causeUndefinedBehavior()に実行されます。

それとも、未定義の動作が引き起こされるポイントは、すべてのケースとすべての実装で完全に異なりますか?

さらに、呼び出された行をコメントアウトした場合causeUndefinedBehavior()、UBは削除されますか、それともUBを含むコードがコンパイルされたため、プログラムに残っていますか?

4

5 に答える 5

4

コードがいくらか示しているように、未定義の動作は、ほとんどの場合、動作が試行されたときの実行時の状態の条件です。コードを少し変更すると、これが痛々しいほど明白になる可能性があります。

void causeUndefinedBehavior()
{
   //any code that causes undefined behavior
   //every time it is run
   char* a = nullptr;
   *a;
}


int main()
{
 srand(time(NULL));
 //code before call
 //...
 if (rand() % 973 == 0)
    causeUndefinedBehavior();
 //code after call
 //...
}

これを1000回以上実行し、UB実行条件をトリップすることはありません。これは、関数自体が明らかにUBであるという事実を変えるものではありませんが、呼び出し側のコンテキストでコンパイル時にそれを検出することは簡単ではありません。

于 2012-10-29T00:30:11.867 に答える
2

「未定義動作」とは、言語定義がプログラムの動作を教えてくれないことを意味します。これは非常に単純なステートメントです。情報はありません。実装が何をするか、何をしないかについて好きなことをすべて推測することができますが、実装がそれが何をするかを文書化しない限り、あなたは推測しているだけです。プログラミングは推測ではありません。それは知ることについてです。プログラムの動作が定義されていない場合は、修正してください。

于 2012-10-29T12:12:52.437 に答える
2

未定義動作の種類にもよると思います。構造体のオフセットなどに影響を与えるものは、未定義の動作を引き起こす可能性があり、その構造体に接触するコードが実行されるたびに表示されます。

ただし、一般に、ほとんどの未定義の動作は実行時に発生します。つまり、そのコードが実行された場合にのみ、未定義の動作が発生します。

たとえば、文字列リテラルを変更しようとすると、未定義の動作が発生します。

char* str = "StackOverflow";
memcpy(str+5, "Exchange", 8);    // undefined behavior

memcpyこの「未定義動作」は、実行されるまで発生しません。それでも完全に正常なコードにコンパイルされます。

もう1つの例は、void以外の戻り型を持つ関数からの戻りを省略することです。

int foo() {
    // no return statement -> undefined behavior.
}

ここでfoo、未定義動作が発生するのはリターンのポイントです。(この場合、x86では、レジスターにたまたま入っていたものはすべてeax、関数の結果の戻り値になります。)

これらのシナリオの多くは、より高いレベルのコンパイラエラーレポートを有効にすることで識別できます(-WallGCCなど)。

于 2012-10-29T00:26:48.547 に答える
1

それは「未定義の振る舞い」ですが、特定のコンパイラーを考えると、ある種の予測可能な振る舞いをします。ただし、これは未定義であるため、さまざまなコンパイラーで、コンパイル/実行時の任意の時点でその動作が発生する可能性があります。

于 2012-10-29T00:26:56.167 に答える
0

これにより、UBを含むプログラムは無意味になる可能性があります

正しくありません。プログラムにUBを「含める」ことはできません。略して「UB」と言うとき:プログラムの振る舞いは未定義です。それのすべて!

したがって、プログラムは潜在的にだけでなく、実際には最初から無意味です。

[intro.execution]/5:整形式プログラムを実行する適合実装は、同じプログラムと同じ入力を持つ抽象マシンの対応するインスタンスの可能な実行の1つと同じ観察可能な動作を生成する必要があります。ただし、そのような実行に未定義の操作が含まれている場合、この国際規格では、その入力を使用してそのプログラムを実行する実装に要件はありません(最初の未定義の操作に先行する操作に関しても)。

于 2018-02-28T15:23:32.217 に答える