何年も前に、これがデフォルトではエラーを生成しないことに気付いて以来 (少なくとも GCC では)、私はいつもその理由を疑問に思っていました。
コンパイラ フラグを発行して警告を生成できることは理解していますが、常にエラーになるべきではないでしょうか? 値を返さない非 void 関数が有効であるのはなぜ意味があるのでしょうか?
コメントでリクエストされた例:
#include <stdio.h>
int stringSize()
{
}
int main()
{
char cstring[5];
printf( "the last char is: %c\n", cstring[stringSize()-1] );
return 0;
}
...コンパイルされます。
ベストアンサー1
C99およびC++標準では、 以外void
の関数は値を返す必要がありますmain
。 の不足しているreturn文main
は定義されます( を返します)。 C++では、以外の0
非関数の最後に実際に実行が達した場合、未定義の動作となりますが、Cでは、呼び出し元がvoid
main
用途戻り値。
つまり、関数は値を返さずに最後まで到達するように見えますが、実際には終了に到達できません}
。ジョン・クーゲルマンの回答は、関数の片側から呼び出される noreturn 関数などの例を示していますif
。これは、実行が実際に終了し、それより前の関数に到達しない場合にだけ、未定義の動作となりますreturn
。その理由は、すべての実際のコードパスが値を返すかどうかを確認するのは非常に難しいため(どの関数が決して戻らないかがわからない場合)、コンパイルあなたの例のような関数ですが、実際にはあなたのmain
例のように呼び出すだけです。
拡張機能として、少なくとも1つのコンパイラ(MSVC)インラインアセンブリで戻り値を設定できるようにするただし、他のほとんどの関数では、 inline を使用する関数で return ステートメントが必要になりますasm
。
からC++11下書き:
§ 6.6.3/2
関数の終わりを超えて流れると [...] 、値を返す関数で未定義の動作が発生します。
§ 3.6.1/5
main
制御が文に遭遇せずにの終わりに達した場合return
、効果は実行されたのと同じになります。return 0;
C++ 6.6.3/2 で説明されている動作は C では同じではないことに注意してください。
gcc を -Wreturn-type オプションで呼び出すと警告が表示されます。
-W戻り型関数が、デフォルトで int になる戻り値の型で定義されている場合は常に警告します。また、戻り値の型が void でない関数内の戻り値のない return ステートメントについても警告します (関数本体の末尾から外れると、値なしで返されるものと見なされます)。また、戻り値の型が void である関数内の式を含む return ステートメントについても警告します。
この警告は、-壁。
興味深いことに、このコードが何を行うか見てみましょう。
#include <iostream>
int foo() {
int a = 5;
int b = a + 1;
}
int main() { std::cout << foo() << std::endl; } // may print 6
このコードは形式的には未定義の動作をしており、実際には呼び出し規約そして建築依存します。特定のシステム、特定のコンパイラでは、最適化を無効にした場合、戻り値は最後の式評価の結果であり、eax
そのシステムのプロセッサのレジスタに格納されます。
これはGCC内部の最適化が無効になっているためだと思われます。戻り値レジスタを選択するステートメントを実装するために必要な場合。C++ モードで最適化を有効にすると、GCC と clang は、この実行パスには未定義の動作が含まれているため、到達不可能であると想定します。命令も発行されないためret
、実行は .text セクションの次の関数に渡されます。もちろん、未定義の動作は、何が起きてもおかしくないことを意味します。