C和C ++函数没有return语句

时间:2015-09-11 00:47:26

标签: c++ c return

在查看工作代码的过程中,我发现了一些(看似)令人反感的代码,其中一个函数具有返回类型,但没有返回。我知道代码有效,但认为它只是编译器中的一个错误。

我编写了以下测试并使用我的编译器运行它(gcc(Homebrew gcc 5.2.0)5.2.0)

#include <stdio.h>

int f(int a, int b) {
  int c = a + b;
}

int main() {
   int x = 5, y = 6;

   printf("f(%d,%d) is %d\n", x, y, f(x,y)); // f(5,6) is 11

   return 0;
}

类似于我在工作中找到的代码,这默认返回函数中执行的最后一个表达式的结果。

我发现this问题,但对答案不满意。我知道使用-Wall -Werror可以避免这种行为,但为什么它是一个选项呢?为什么仍然允许?

4 个答案:

答案 0 :(得分:12)

“为什么这仍然允许?”它不是,但一般来说,编译器不能证明你正在做它。考虑这个(当然非常简化)的例子:

// Input is always true because logic reason
int fun (bool b) {
    if (b) {
        return 7;
    }
}

甚至是这个:

int fun (bool b) {
    if (b) {
        return 7;
    }
    // Defined in a different translation unit, will always call exit()
    foo();
    // Now we can never get here, but the compiler cannot know
}

现在第一个例子可以流出结尾,但只要函数“正确”使用它就永远不会;而第二个不能,但编译器不能知道这一点。所以编译器会通过使这个错误打破“工作”和合法,尽管可能是愚蠢的代码。

现在您发布的示例略有不同:此处,所有路径都流出结束,因此编译器可以拒绝或忽略此功能。然而,它会破坏依赖于生产代码中的编译器特定行为的真实世界代码,并且人们不喜欢它,即使它们是错误的。

但最终,流出非void函数的结尾仍然是未定义的行为。它可能适用于某些编译器,但它不是,也绝不保证。

答案 1 :(得分:4)

具有返回类型但没有返回语句的函数的结果是未定义的(除了在带有main的C ++中,返回值为0)。它也不是语法错误,因为语法使用一般函数表示一个适用于值返回和void函数的函数。

这里发生的事情是,最后一个表达式的结果存储在编译器用于函数返回值的同一寄存器(在x86,EAX或RAX上)中。当函数返回时,返回指令单独留下该寄存器,并且调用代码只是假设该值具有该函数的返回值。

答案 2 :(得分:4)

这不是编译器中的错误,但代码显然很糟糕。在x86架构上,(R | E)AX用作累加器寄存器,也用作返回值。

让我们来看看完全未经优化的反汇编:https://goo.gl/TihXpa

  • 您会看到f()的代码确实使用了eax来存储添加结果。

  • 然而 ...继续使用-O1(或任何更积极的优化级别)作为编译器选项(右上方框),看看现在发生了什么

...我们发现编译器已经正确地意识到函数没有明确地返回它的结果,它只是变成了无操作。

因此,这段令人讨厌的代码是一个完美的例子,它可以像调试版本一样工作,但在应用任何优化时都会失败。

答案 3 :(得分:1)

  

在计算机体系结构级别:如果内存中存在默认位置,在简单计算后存储结果,则可以使用正确答案返回(无意中)此内存。

这是:

  

至少对于x86,此函数的返回值应该在eax寄存器中。那里的任何东西都会被调用者视为返回值。   
因为eax用作返回寄存器,所以它通常用作&#34; scratch&#34;由calee注册,因为它不需要保留。这意味着它很可能被用作任何局部变量。因为它们两者在最后是相等的,所以更有可能将正确的值保留在eax中。

检查here类似主题。