16

関数に 以外の戻り値の型がvoidあり、関数が何も返さない場合、コンパイラはガベージ値 (おそらく初期化されていない値と見なされる) を返すと思います。コンパイル時に発生するのに、なぜエラーが表示されないのでしょうか?

例えば、

int func1() {
    return; // error
}

int func2() {
    // does not return anything
}

2 番目func2はエラーをスローするはずですが、そうではありません。それには理由がありますか?私の考えでは、それは初期化されていない値と見なすことができるので、2番目のケースでエラーをスローする必要がある場合は、値が初期化されていない場合はエラーをスローする必要があります。

  int i;  // error
  int i = 6;  // okay

何か考えがありますか、それともこれは重複した質問ですか? 私はあなたの助けに感謝します。

4

4 に答える 4

23

C++ では、このようなコードの動作は未定義です。

[stmt.return]/2 ... 関数の最後をフローすることは、値を持たないリターンと同じです。これにより、値を返す関数で未定義の動作が発生します。...

ほとんどのコンパイラは、質問と同様のコードに対して警告を生成します。

C++ 標準では、これがコンパイル時エラーである必要はありません。一般的なケースでは、コードが実際に関数の最後で実行されるかどうか、または関数が例外 (または longjmp によって終了するかどうか) を正しく判断することが非常に難しいためです。または同様のメカニズム)。

検討

int func3() {
    func4();
}

がスローされる場合func4()、このコードは問題ありません。コンパイラは (個別のコンパイルのため) の定義を認識できない可能性がありfunc4()、スローするかどうかを判断できません。

さらに、コンパイラが がfunc4()スローしないことを証明できたとしてもfunc3()、合法的にプログラムを拒否する前に、 が実際に呼び出されることを証明する必要があります。このような分析には、プログラム全体の検査が必要であり、個別のコンパイルとは互換性がなく、一般的なケースでは不可能です。

于 2012-03-30T02:10:29.827 に答える
12

C では、N1256 6.9.1p12を引用します。

関数を終了する}に到達し、関数呼び出しの値が呼び出し元によって使用された場合、動作は未定義です。

そのため、void 以外の関数が値を返さないことは正当ですが (ただし、悪い考えです)、そうであり、呼び出し元が結果を使用しようとした場合、動作は未定義です。必ずしも任意の値を返すとは限らないことに注意してください。標準に関する限り、何でも可能です。

ANSI C より前にはvoidキーワードがなかったため、値を返さない関数を記述する方法は、戻り値の型を省略して暗黙的に return にすることintでした。return値を返す関数でステートメントを要求すると、古いコードが壊れていました。また、すべてのコード パスがreturnステートメントにヒットしたかどうかを判断するために、コンパイラによる追加の分析が必要になります。このような分析は最新のコンパイラにとっては合理的ですが、C が最初に標準化されたときは過度の負担だった可能性があります。

C++ はもう少し厳密です。C++ の場合:

関数の最後を流れることは、値を持たない戻りと同じです。これにより、値を返す関数で未定義の動作が発生します。

そのため、呼び出し元が (存在しない) 結果を使用しようとするかどうかにかかわらず、動作は未定義です。

C および C++ コンパイラは、ステートメントの欠落や、ステートメントを実行せずに関数の末尾にある制御パスについて警告することはできますが、それぞれの標準ではそうする必要はありません。returnreturn

于 2012-03-30T02:11:06.080 に答える
6

C では、呼び出し元のコードが戻り値を使用しようとしない限り、非 void 関数が値を返さずに終了することは実際には合法です。

一方、return式のないステートメントは、非 void 関数に表示することはできません。

C99 標準の関連部分は、最初のケースの §6.9.1 です。

関数}を終了する に到達し、関数呼び出しの値が呼び出し元によって使用された場合、動作は未定義です。

2 番目のケースの §6.8.6.4:

式のreturnないステートメントは、戻り値の型が である関数にのみ出現しますvoid

于 2012-03-30T02:09:20.640 に答える
2

両方の関数の形式が正しくありません。それらの違いは、未定義の動作である間にステートメントを使用するfunc1方法に関する規則に違反していることです。あなたのステートメントは違法であり、実装はこれを診断する必要があります。あなたに return ステートメントがないことは、未定義の動作です。ほとんどのコンパイラはこれを診断しますが、診断する必要はありません。returnfunc2returnfunc1func2

于 2012-03-30T02:10:02.800 に答える