3

新しいプロジェクトで再利用する目的で古い C コード (以下にリスト) を調べていたところ、最後の return ステートメントを省略していたことに気付きました。奇妙な点は、ルーチンが完全に機能し、正しいファイル ポインターを返したことです。誰かが私にこれがなぜなのか説明できますか?

 FILE* openforwrite(char *name, int binary)
 {
    //broken out from main to keep it tidy and allow multiple output files.
    FILE *file;
    //first see if it exists
    file = fopen(name,"r");
    if (file)
    { // it does, delete it
        fclose(file);
        if(remove(name)) bail("Output file already exists and cannot be deleted.");
    }
    //now lets re-create and open it for writing
    if (binary)
        file = fopen(name, "wb");
    else
        file = fopen(name, "w");

    //check it actually opened
    if (!file)
        bail("Error opening output file.");

    //and pass the pointer back
    return file; // <-- I had omitted this line initially but the routine still worked
 }
4

3 に答える 3

3

呼び出しの戻り値は、戻り値にfopen一般的に使用されるレジスタ (例: ) にファイル ハンドルを配置することになりますeax。関数が終了する前にそのレジスタ値が何も変更されていない場合、呼び出し元は引き続き使用できる可能性があります。たとえば、関数fopenの終了後と終了前にもう 1 つの関数呼び出しがあった場合、レジスタが上書きeaxされ、確実に失敗した可能性があります。他の人が言ったように、それは未定義の動作です。それにもかかわらず、最初は非常に不可解な状況です (そしてかなり興味深い)。

于 2012-06-14T22:12:06.623 に答える
1

たまたまうまくいっただけです。コンパイラは、スタックを使用して関数に引数を渡し、その戻り値を受け取ります。また、ローカル変数と計算中の一時変数にもスタックを使用します。関数が返されたとき、呼び出し元は戻り値のスタック内の特定の位置を調べました。その値にはたまたまファイル ポインター値が含まれていました。これは、関数が計算した最後の式だったからです。

いかなる状況でも、これが再びこのように機能するとは決して考えないでください。

コンパイラのバージョンが異なる、最適化が異なる、またはコンパイラがランダムにレッスンを教えることにしたなど、さまざまな理由で壊れる可能性があります。

于 2012-06-14T22:04:17.800 に答える
0

問題は、未定義の動作を呼び出したことです。動作しているように見えたり、クラッシュしたり、バッファ オーバーフローが発生した場合にファイルを削除したりできます。

于 2012-06-14T22:04:16.273 に答える