函数的默认返回值1,返回类型为int?

时间:2017-07-13 17:46:14

标签: c++ c

在此特定代码中,我无法看到它是如何输出1的。控件到达函数的末尾返回int类型而不会遇到return语句,因此不应该存在运行时错误。 我尝试将其他一些值传递给函数,所有值都打印相同的值1,因为b0之前最终为奇数。

我尝试搜索int返回功能的默认返回值,但无法得到满意的答案。有人说,默认的返回值是0,那么为什么1是这里的输出?

int fun(int a, int b) {
    if (b == 0) {
        return 0;
    }
    if (b % 2 == 0) {
        return fun(a + a, b / 2);
    }
}

int main() {
    printf("%d", fun(6, 3));
    return 0;
}

5 个答案:

答案 0 :(得分:8)

未返回返回类型不是void的函数的值是未定义的行为(main除外 - main返回0)。未定义的行为意味着任何事情都可能发生。

为什么会得到1?在x86上,返回int的函数返回寄存器eax的值。因此,如果您未在函数中返回值,则函数将返回退出时eax包含的任何值。

这是一个可能的解释:在b%2,编译器将b放入eaxand将其放入1. and的结果可以是01eax将包含其中一个值。如果结果为1,则fun退出而不返回。因此,退出时,eax包含1。这是从函数返回的值。

注意:如果启用警告,编译器将发出警告。

注2:某些编译器在此处设置运行时错误,正如您所期望的那样(例如,clang执行此操作)。

注3:某些编译器会为此发出编译错误(例如MSVC)。

答案 1 :(得分:5)

在C ++中,从应该返回值而不返回值的函数的末尾掉下来是未定义的行为。您可能得到0,可能得到1,或者可以存储在返回类型中的任何其他值。

唯一不适用的是from tkinter.simpledialog import askstring from tkinter.messagebox import showinfo name = askstring('Name', 'What is your name?') showinfo('Hello!', 'Hi, {}'.format(name)) 。标准中有一个条款规定,main如果没有隐含main将具有隐式return 0;

答案 2 :(得分:4)

  

默认返回值为0

仅适用于main,这是特殊的。

对于具有非void返回类型的其他函数,必须返回一个值。周期。

如果不这样做会导致不确定的行为,例如自发地翻转内衣或切断妈妈的头发。或者获得1

所以:

int fun(int a, int b)
{
    if (b == 0)
       return 0;

    if (b % 2 != 0)
       return 1;

    return fun(a + a, b / 2);
}

int main()
{
    printf("%d", fun(6,3));
}

答案 3 :(得分:2)

正如其他人所指出的那样,行为是未定义的:在没有int语句的情况下从return返回函数的末尾掉落具有未定义的行为。它可以返回1,或2或其他任何东西......事实上,根据它的编译方式,它确实会发生!

以下是由Godbolt's fantastic compiler explorer生成的gcc 7.1 -O2 64位的程序集输出:

fun(int, int):
        test    esi, esi
        je      .L5
        test    sil, 1
        je      .L8
        rep ret
.L8:
        sub     rsp, 8
        mov     eax, esi
        shr     eax, 31
        add     esi, eax
        sar     esi
        add     edi, edi
        call    fun(int, int)
        add     rsp, 8
        ret
.L5:
        mov     eax, esi
        ret
.LC0:
        .string "%d"
main:
        sub     rsp, 8
        mov     esi, 3
        mov     edi, 6
        call    fun(int, int)
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        add     rsp, 8
        ret

函数fun的返回值存储在寄存器eax中。仔细分析表明,当fun(6, 3)调用时,fun实际上不会修改eax。在调用main()之前,fun(6, 3)不会修改此寄存器,因此它必须来自C启动代码。我怀疑eax包含argc main()参数的值,1加上命令行传递的参数数量。您可以尝试使用参数调用程序,看看它是否输出2等。

当然,这只是猜测

  • 您的编译器可能会生成以不同原因输出1的代码。
  • C启动代码可能会将eax设置为1以解决其他原因。

在godbolt在线编译器上尝试不同的编译器和优化设置,看看它产生了什么。例如clang -O2编译fun()以始终返回0

答案 4 :(得分:1)

C标准允许声明和定义的函数返回一个值,在没有return语句的情况下结束。调用这样的函数有明确定义的行为:

#include <stdio.h>

int foo(void) {
    printf("Hello world");
}

int main(void) {
    foo();
}

但是,在C using 中,未通过return语句返回值的函数的返回值具有未定义的行为。这在C11 6.9.1p12

中明确提到
  

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

因此在你的例子中,

fun(6, 3);

很好,就像整个函数定义一样,但是使用

中的返回值
printf("%d", fun(6, 3));

将召唤nasal demons

但是,C ++是一个不同的野兽,省略了return语句本身有未定义的行为 - 但GCC似乎在这种情况下忽略了它 - 也许是为了允许用C ++编译器编译(可疑)C代码。