函数返回值而没有return语句

时间:2011-01-10 08:25:43

标签: 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;
        }
    }
}

7 个答案:

答案 0 :(得分:31)

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

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

答案 1 :(得分:15)

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

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

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

我用gcc测试了它:

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

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

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

答案 2 :(得分:4)

如果定义了一个函数以返回值,但没有返回值,并且调用函数尝试使用返回值,则调用undefined behavior

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

  

如果达到了终止函数的},并且   函数调用由调用者使用,其行为是不确定的。

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

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

答案 3 :(得分:3)

在x86上,返回值存储在EAX寄存器中,此编译器也“意外地”使用它来存储算术运算的结果(或至少减法)。您可以通过查看编译器生成的程序集来检查这一点。我同意kriss - 你不能认为总是这样,所以最好明确指定返回值。

答案 4 :(得分:0)

GCC在这种情况下粘贴“ret”指令,而clang粘贴“ud2”并且应用程序在运行时崩溃。

答案 5 :(得分:0)

官方语言:

6.9.1函数定义
...
12如果到达终止函数的},并且函数调用的值由 调用方,行为是不确定的。

其中“未定义的行为”表示:

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

2注意可能的不确定行为范围包括完全不可预测地完全忽略情况 结果,在翻译或程序执行过程中表现为 环境(带有或不带有诊断消息)终止翻译或 执行(发出诊断消息)。

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

C 2011 Online Draft

信不信由你,不需要键入void以外的内容的函数才具有return语句。它不是由语言语法强制执行的,并且没有约束,非void函数必须包含return语句。唯一的限制是,如果存在,则return函数中的void语句不返回任何表达式的值,并且非{{{1 }}函数必须返回表达式的值。

为什么会这样?

C最初没有return数据类型,并且没有办法指定仅出于其副作用而没有返回值的子例程。没有返回“ nothing”的好方法,因此不需要void语句。 C此时也具有“隐式void”声明-您可以定义不带类型的函数体,并且编译器会假定将其键入为return

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 } 。只要调用者不尝试使用 foo的不存在的返回值就可以。因此,开发出一种约定俗成的约定,其中没有明确键入“过程”(仅出于副作用而执行的功能),并且没有int语句。

由于遗留代码永远存在,因此即使在C99中删除了隐式foo声明,在最新版本的C标准中对于return语句的行为也没有更改。

答案 6 :(得分:-4)

如果使用指针,则不需要return语句。通常,您只能通过Return语句返回一个值,但如果您使用指针,则可以返回您想要的数量。

scanf(“%d”,&amp; x1);在那里你给了一个X1的地址,而不是X1值。指针工作宽度地址。你可以阅读书籍,学习如何使用指针。