1. ホーム
  2. c++

[解決済み] 値を返さずに非void関数の最後を流しても、コンパイラエラーが発生しないのはなぜですか?

2022-04-22 08:43:19

質問

何年も前に、これが(少なくともGCCでは)デフォルトでエラーを生成しないことに気づいて以来、わたしはいつもなぜなのか不思議に思っていました。

コンパイラーフラグを発行して警告を出すのはわかるが、常にエラーにするべきではないのか?値を返さない非void関数が有効であることに、なぜ意味があるのでしょうか?

コメントでリクエストのあった例です。

#include <stdio.h>
int stringSize()
{
}

int main()
{
    char cstring[5];
    printf( "the last char is: %c\n", cstring[stringSize()-1] ); 
    return 0;
}

...コンパイルします。

解決方法は?

C99規格やC++規格では、関数が値を返す必要はありません。値を返す関数に欠けている return 文が定義されることになります(返すために 0 )の中でだけ main 関数を使用します。

その根拠としては、すべてのコードパスが値を返すかどうかをチェックするのは非常に難しく、また、組み込みアセンブラやその他のトリッキーな方法で戻り値を設定することも可能であることなどが挙げられます。

から C++11 ドラフト

§ 6.6.3/2

関数の末尾を流すと [...] 値を返す関数では未定義の動作になる。

§ 3.6.1/5

の末尾に制御が到達した場合 main に遭遇することなく return ステートメントを実行すると、次のような効果があります。

return 0;

C++ 6.6.3/2で説明されている動作は、C言語では同じではないことに注意してください。


gccは-Wreturn-typeオプションを付けて呼び出すと警告を出します。

-Wreturn-type 関数が return-type で定義されている場合に警告を表示します。 のデフォルトは int です。また return-valueを指定しないreturnステートメント でない関数で、その戻り値の型が void (このセクションの最後にある 関数本体を返すと 値なし)、およびreturn を式で指定することができます。 関数の戻り値が void である場合。

この警告が有効になるのは -壁 .


好奇心で、このコードが何をするのか見てみましょう。

#include <iostream>

int foo() {
   int a = 5;
   int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

このコードは形式的に未定義の動作であり、実際には 呼び出し規約 アーキテクチャ に依存します。ある特定のシステム、ある特定のコンパイラでは、返り値は最後の式の評価結果で eax レジスタに格納されます。