29

私がちょうど出くわしたいくつかの古いコード:

MLIST * new_mlist_link()
{
    MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
    new_link->next  = NULL;
    new_link->mapi  = NULL;
    new_link->result = 0;
}

これはリンクリストを作成するために呼び出されていましたが、ステートメントがないことに気づきました。

return new_link;

そこにreturnステートメントがなくても、リストは適切に作成されました。なぜこれが起こったのですか?

編集:プラットフォーム:Mandriva200964ビットLinux2.6.24.7-サーバーGCC4.2.3-6mnb1

編集:おかしい...このコードは、約5つの異なるLinuxインストール、すべての異なるバージョン/フレーバー、およびMacでも正常に実行されました。

4

8 に答える 8

35

32ビットWindowsでは、ほとんどの場合、関数からの戻り値はEAXレジスタに残されます。他のOSでも同様の設定が使用されていますが、もちろんコンパイラ固有です。この特定の関数は、おそらく同じ場所にnew_link変数を格納しているため、戻り値なしで戻った場合、その場所の変数は呼び出し元によって戻り値として扱われました。

これは移植性がなく、実際に行うのは非常に危険ですが、Cでのプログラミングをとても楽しくする小さなことの1つでもあります。

于 2010-05-05T20:24:27.030 に答える
7

通常は最後に呼び出された関数の戻り値を格納するEAXレジスタを使用した可能性があります。これはまったく良い習慣ではありません!この種のものの振る舞いは未定義です。しかし、仕事を見るのはクールです;-)

于 2010-05-05T20:26:34.440 に答える
5

この問題を回避するには、次を使用します。

-Wreturn-type

関数がデフォルトでintに設定されたreturn-typeで定義されている場合は常に警告します。また、return-typeがvoidではない関数のreturn-valueのないreturnステートメント(関数本体の終わりから外れると、値なしで戻ると見なされます)、および関数の式のあるreturnステートメントについて警告します。 return-typeはvoidです。

-Werror=return-type上記をエラーに変えるには:

指定された警告をエラーにします。警告の指定子が追加されます。たとえば、-Werror = switchは、-Wswitchによって制御される警告をエラーに変換します。このスイッチは負の形式を取り、特定の警告の-Werrorを無効にするために使用されます。たとえば、-Wno-error = switchは、-Werrorが有効な場合でも、-Wswitch警告をエラーにしません。-fdiagnostics-show-optionオプションを使用すると、制御可能な各警告を、それを制御するオプションで修正して、このオプションで何を使用するかを決定できます。

GCCの警告オプションから)

于 2010-05-05T23:55:59.693 に答える
5

基本的には運です。どうやら、コンパイラは、戻り値を貼り付けるのと同じ場所にnew_linkを貼り付けているようです。

于 2010-05-05T20:25:29.070 に答える
1

これは偶然に機能します。あなたはそれに頼るべきではありません。

于 2010-05-05T20:26:17.427 に答える
1

ほとんどの場合、バグを見つけるのが非常に困難になります。どこで読んだかはわかりませんが、returnステートメントを入力し忘れると、ほとんどのコンパイラはデフォルトでvoidを返すことを思い出します。

簡単な例を次に示します。

#include <iostream>

using namespace std;

int* getVal();

int main()
{
        int *v = getVal();
        cout << "Value is: " << *v << endl;
        return 0;
}

int* getVal()
{
        // return nothing here
}

私にとっては、これも機能します。ただし、実行すると、セグメンテーション違反が発生します。ですから、それは本当に未定義です。コンパイルしたからといって、動作するわけではありません。

于 2010-05-05T20:40:07.553 に答える
0

C言語が作成された1940年代には、returnキーワードがなかったため、これは機能します。C43 MINSI標準の「機能」セクションを見ると、(とりわけ)この件について次のように述べられています。

16.4.3b For backwards compatibility the EAX register MUST be used to return
        the address of the first chunk of memory allocated by malloc.

</humour>

于 2010-05-05T21:21:01.243 に答える
-1

おそらく偶然の一致:

関数の戻り値のためのスペースは、事前に割り当てられます。その値は初期化されていないため、構造体に割り当てられたメモリと同じヒープ上のスペースを指している可能性があります。

于 2010-05-05T20:25:42.690 に答える