函数返回值而没有return语句

Pas*_*yer 19 c return-value

为什么下面的代码输出正确?int GGT没有return语句,但代码确实有用吗?没有设置全局变量.

#include <stdio.h>
#include <stdlib.h>

int GGT(int, int);

void main() {
    int x1, x2;
    printf("Bitte geben Sie zwei Zahlen ein: \n");
    scanf("%d", &x1);
    scanf("%d", &x2);
    printf("GGT ist: %d\n", GGT(x1, x2));
    system("Pause");
}

int GGT(int x1, int x2) {
    while(x1 != x2) {
        if(x1 > x2) {
            /*return*/ x1 = x1 - x2;
        }
        else {
            /*return*/ x2 = x2 - x1;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

rus*_*lik 34

至少对于x86,此函数的返回值应该在eax寄存器中.那里的任何东西都会被调用者视为返回值.

因为eax它被用作返回寄存器,所以它通常被callee用作"scratch"寄存器,因为它不需要保留.这意味着它很可能被用作任何局部变量.因为它们两者在最后是相等的,所以更可能保留正确的值eax.


kri*_*iss 16

它应该不起作用,当然不适用于所有编译器和目标操作系统,即使它适用于您的.

可能的解释是返回int的函数总是返回一些东西,它通常是寄存器的内容.可能会发生用于返回值的寄存器在您的情况下用于计算从函数返回之前的最后一个表达式(在x86目标上,当然是eax).

这就是说,允许检测到没有返回的优化编译器完全删除该函数的代码.此后,您在激活更高优化级别时看到(可能)消失的效果.

我用gcc测试了它:

没有优化的gcc:输入10,20 - >结果是10

gcc -O1输入10,20 - >结果为1

gcc -O2输入10,20 - >结果为0


dbu*_*ush 7

如果一个函数被定义为返回一个值但没有返回值,并且调用函数尝试使用返回值,则调用未定义行为

这在C 标准的第 6.9.1p12 节中有详细说明:

如果}到达终止函数的 ,并且调用者使用了函数调用的值,则行为未定义。

在这种情况下,您很“幸运”,程序似乎可以正常工作,但不能保证这一点。如果您使用不同的优化设置或完全不同的编译器进行编译,您最终可能会得到不同的结果。

所以这个故事的寓意是:如果函数说它返回一个值,那么总是返回一个值。


Joh*_*ode 7

官方原话:

6.9.1 函数定义
...
12 如果}到达终止函数的位置,并且调用者使用函数调用的值,则行为未定义。

其中“未定义的行为”意味着:

1未定义行为
在使用不可移植或错误的程序结构或错误数据时出现的行为,而本国际标准对此没有强加任何要求。

2 注:可能的未定义行为包括完全忽略结果不可预测的情况,到在翻译或程序执行过程中的行为。环境特征的记录方式(发出或不发出诊断消息)到终止翻译或执行(发出诊断消息)。

3 示例 未定义行为的一个示例是整数溢出的行为。

C 2011 在线草稿

不管你相信与否,输入除 之外的内容的函数void不需要语句return。它不是由语言语法强制执行的,并且不存在非void函数必须包含return语句的限制。唯一的限制是,如果存在,return函数中的语句void不会返回任何表达式的值,并且returnvoid函数中的语句必须返回表达式的值。

为什么会这样?

C 最初没有void数据类型,也没有办法指定一个只因其副作用而执行且不返回值的子例程。没有返回“nothing”的好方法,因此return不需要该声明。C 此时也有“隐式int”声明 - 您可以定义一个没有类型的函数体,编译器会假设它是类型化的int

foo( a, b )   // old style parameter declarations
  int a;      // still legal, but no longer really used
  char *b;    // for very good reasons
{
  // do something interesting with a and b
}
Run Code Online (Sandbox Code Playgroud)

foo隐式类型化为 return int,即使没有显式返回任何值。只要调用者不尝试使用 foo不存在的返回值就可以。因此,形成了一种约定,其中“过程”(仅为副作用而执行的函数)没有明确键入,也没有任何return声明。

由于遗留代码是永久的,因此即使在 C99 中删除了隐式声明,在最新版本的 C 标准中,与语句 相关的行为也return没有改变。int


小智 5

在x86上,返回值存储在EAX寄存器中,该编译器“偶然地”还使用该值存储算术运算(或至少减法)的结果。您可以通过查看编译器生成的程序集来进行检查。我同意kriss-您不能假设情况总是如此,因此最好明确指定返回值。