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结束之前和之后还有一个函数调用,那么它很可能会覆盖eax寄存器并且肯定会失败。正如其他人所说,这是未定义的行为。尽管如此,这最初是一个非常令人费解的情况(而且相当有趣)。

于 2012-06-14T22:12:06.623 回答
1

它只是碰巧起作用了。编译器使用堆栈将参数传递给函数,并接收它们的返回值。它还在计算期间将堆栈用于局部变量和临时变量。当函数返回时,调用者查看堆栈中的特定位置以获取返回值。该值恰好包含文件指针值,因为这是您的函数计算的最后一个表达式。

在任何情况下,都不要假设这会再次以这种方式工作。

它可能由于多种原因而中断,包括不同的编译器版本、不同的优化,或者只是因为编译器随机决定给你上一课。

于 2012-06-14T22:04:17.800 回答
0

问题是您调用了未定义的行为。它似乎可以工作,它可能会崩溃,并且在缓冲区溢出的情况下,它可以删除文件。

于 2012-06-14T22:04:16.273 回答