在此特定代码中,我无法看到它是如何输出1
的。控件到达函数的末尾返回int
类型而不会遇到return
语句,因此不应该存在运行时错误。
我尝试将其他一些值传递给函数,所有值都打印相同的值1
,因为b
在0
之前最终为奇数。
我尝试搜索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;
}
答案 0 :(得分:8)
未返回返回类型不是void
的函数的值是未定义的行为(main
除外 - main
返回0)。未定义的行为意味着任何事情都可能发生。
为什么会得到1?在x86上,返回int
的函数返回寄存器eax
的值。因此,如果您未在函数中返回值,则函数将返回退出时eax
包含的任何值。
这是一个可能的解释:在b%2
,编译器将b
放入eax
,and
将其放入1. and
的结果可以是0
或1
,eax
将包含其中一个值。如果结果为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
的代码。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代码。