値を返さずに非 void 関数の最後から流れてもコンパイラ エラーが発生しないのはなぜですか? 質問する

値を返さずに非 void 関数の最後から流れてもコンパイラ エラーが発生しないのはなぜですか? 質問する

何年も前に、これがデフォルトではエラーを生成しないことに気付いて以来 (少なくとも 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では、呼び出し元がvoidmain用途戻り値。

つまり、関数は値を返さずに最後まで到達するように見えますが、実際には終了に到達できません}ジョン・クーゲルマンの回答は、関数の片側から呼び出される 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 セクションの次の関数に渡されます。もちろん、未定義の動作は、何が起きてもおかしくないことを意味します。

おすすめ記事