【问题标题】:Weird behaviour when returning FILE pointer from a C function从 C 函数返回 FILE 指针时的奇怪行为
【发布时间】:2012-06-14 21:58:45
【问题描述】:

我正在检查一些旧的 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
 }

【问题讨论】:

  • 您可以在文件上使用stat() 来查看它是否存在,而不是打开/关闭。请注意,您的代码是活泼的,如果在关键应用程序中使用,可能会为某些人敞开大门,使用计时攻击将符号链接滑入指定文件名的位置,并让您的应用程序在应该乱写的地方乱写数据
  • 我很惊讶它编译了——似乎一个具有非 void 返回类型且不返回任何内容的函数无法编译。
  • 谢谢你,Marc,这点很好,我下次使用时会这样做。
  • @jedwards:阅读here,了解为什么它在没有返回语句的情况下编译。
  • 我依稀记得最近看到这个问题被问了很多,但是除了this one之外我找不到其他例子

标签: c file-io


【解决方案1】:

fopen 调用的返回值最终会将文件句柄放入通常用于返回值的寄存器中(例如,eax)。如果在函数退出之前没有改变该寄存器的值,它仍然可供调用者使用。例如,如果您在fopen 之后和函数结束之前还有一个函数调用,那么它可能会覆盖eax 寄存器并且肯定会失败。正如其他人所说,这是未定义的行为。尽管如此,这最初是一个非常令人费解的情况(而且相当有趣)。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-17
        • 2020-11-28
        • 2012-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多