24

StrawberryPerlで取得したWindows用のg++のバージョンから奇妙な動作が発生しました。これにより、returnステートメントを省略できました。

boundTag:と呼ばれる2つのポインターで構成される構造を返すメンバー関数があります。

struct boundTag Box::getBound(int side) {
    struct boundTag retBoundTag;
    retBoundTag.box = this;
    switch (side)
    {
        // set retBoundTag.bound based on value of "side"
    }
}

この関数は私にいくつかの悪い出力を与えました、そして私はそれがreturnステートメントを持っていないことを発見しました。戻るretBoundTagつもりでしたが、実際にreturnステートメントを書くのを忘れていました。追加したら、return retBoundTag;すべて問題ありませんでした。

しかし、私はこの関数をテストし、それから正しいboundTag出力を得ました。今でも、returnステートメントを削除すると、g++は警告なしにコンパイルします。WTF?戻ると思いretBoundTagますか?

4

3 に答える 3

21

関数[Except ]でreturnステートメントを省略し、コードで戻り値を使用すると、UndefinedBehaviorが呼び出されます。non-voidmain()

ISO C++-98[セクション6.6.3/2]

式を含むreturnステートメントは、値を返す関数でのみ使用できます。式の値は、関数の呼び出し元に返されます。必要に応じて、式は、それが表示される関数の戻り型に暗黙的に変換されます。returnステートメントには、一時オブジェクト(class.temporary)の作成とコピーを含めることができます。関数の終わりから流れ出るのは、値のない戻りと同じです。これにより 、値を返す関数で未定義の動作が発生します。

例えば

int func()
{
    int a=10;
    //do something with 'a'
    //oops no return statement
}


int main()
{
     int p=func();
     //using p is dangerous now
     //return statement is optional here 
}

通常、g++は。を与えますwarning: control reaches end of non-void function-Wallオプションでコンパイルしてみてください。

于 2010-08-04T02:33:20.120 に答える
17

returnCおよびC++では、ステートメントは必要ありません。関数が無限ループに入ったり、例外をスローしたりするため、必要ない場合があります。

Prasoonは、標準の関連部分をすでに引用しています。

[セクション6.6.3/2]

式を含むreturnステートメントは、値を返す関数でのみ使用できます。式の値は、関数の呼び出し元に返されます。必要に応じて、式は、それが表示される関数の戻り型に暗黙的に変換されます。returnステートメントには、一時オブジェクト(class.temporary)の作成とコピーを含めることができます。関数の終わりから流れ出るのは、値のない戻りと同じです。これにより、値を返す関数で未定義の動作が発生します。

つまり、returnステートメントがなくても問題ありません。しかし、戻らずに関数の最後に到達することは未定義の動作です。

コンパイラはこれらのケースを常に検出できるとは限らないため、コンパイルエラーである必要はありません(実行が実際に関数の最後に到達するかどうかを判断するには、停止問題を解決する必要があります)。これが発生した場合に何が起こるかは、単に未定義です。動作しているように見える場合があり(呼び出し元の関数は、戻り値があるはずの場所にあるガベージ値を確認するだけなので)、クラッシュしたり、デーモンが鼻から飛び出したりする可能性があります。

于 2010-08-04T12:15:07.403 に答える
3

C ++コンパイラは、関数がreturnステートメントを実行できない場合を常に検出できるとは限りませんが、通常は検出できます。

明るい面としては、少なくともg ++を使用すると、コマンドラインコンパイラオプション「-Wreturn-type」を使用してこれを簡単に検出できます。あなたはそれを有効にすることを覚えておく必要があります。(「-Wall」を使用すると有効になります。)

于 2012-10-17T17:31:18.813 に答える