编程 returns 值 -1073741571 而不是永远
Program returns a value of -1073741571 instead of going forever
我正在学习函数并决定创建一个循环,其中两个函数(在本例中为 funcA
和 funcB
)永远相互调用,但它会在一段时间后停止执行。
代码如下所示:
#include <iostream>
void funcA(); //forward declaration
//funcB calls funcA
void funcB()
{
funcA();
}
//funcA prints 1 and calls funcB again
void funcA()
{
std::cout<<1;
funcB();
}
//main calls funcB
int main()
{
funcB();
return 0;
}
返回值为-1073741571
(0xC00000FD
)。你能解释为什么会这样吗?
虽然理论上这会永远持续下去,但问题是每次调用函数时都需要在称为 'stack' 的东西上保留一些内存。最终 'stack' 上不再有 space,您将得到 WhosebugException。 0xC00000FD
是错误代码 windows 用来告诉您 WhosebugException 发生了
无论何时调用一个函数,程序都会保留少量 space 来保存该函数的信息(space 对于局部变量,return 之后的位置信息函数退出等)。该内存是从称为调用堆栈(或简称为“堆栈”)的区域分配的,并且在函数完成时 returned 到堆栈 运行ning.
堆栈通常具有固定的小尺寸。如果你有一个很长的调用链(通常以数万次调用来衡量),你可以 运行 出栈 space 并且程序将终止并出现称为堆栈溢出的错误。这就是您的程序中发生的事情。
一般来说,如果你有递归(或者在你的情况下,相互递归)函数,你需要确保递归深度不会因为某些定义“太大, ”或者这种事情可能会发生。在某些特殊情况下,某些编译器可以识别您正在编写递归代码并将其转换为不分配多个堆栈帧的代码(有关更多详细信息,请参阅“尾调用消除”),但这是例外而不是规则。
好的,因为这是 Windows 10 上的 gcc,请看一下 goodbolt
在没有启用任何优化的情况下,两个函数都被显式调用。
b():
push rbp
mov rbp, rsp
call foo()
call a()
nop
pop rbp
ret
a():
push rbp
mov rbp, rsp
call b()
nop
pop rbp
ret
正如其他答案指出的那样,每次调用都会在堆栈信息中留下如何返回调用函数的函数的信息。
现在因为函数 never return 这个信息永远不会从堆栈中删除,而是不断添加。结果,您得到了堆栈溢出,在 Windows 上由值 0xC00000FD
.
指示
现在,如果您启用优化 (-O2
),编译器能够识别出这是无限循环(使用称为尾递归的技术)。
b():
sub rsp, 8
.L2:
call foo()
jmp .L2
a():
sub rsp, 8
.L6:
call foo()
jmp .L6
因此,启用优化后,您将获得预期的无限循环。
我正在学习函数并决定创建一个循环,其中两个函数(在本例中为 funcA
和 funcB
)永远相互调用,但它会在一段时间后停止执行。
代码如下所示:
#include <iostream>
void funcA(); //forward declaration
//funcB calls funcA
void funcB()
{
funcA();
}
//funcA prints 1 and calls funcB again
void funcA()
{
std::cout<<1;
funcB();
}
//main calls funcB
int main()
{
funcB();
return 0;
}
返回值为-1073741571
(0xC00000FD
)。你能解释为什么会这样吗?
虽然理论上这会永远持续下去,但问题是每次调用函数时都需要在称为 'stack' 的东西上保留一些内存。最终 'stack' 上不再有 space,您将得到 WhosebugException。 0xC00000FD
是错误代码 windows 用来告诉您 WhosebugException 发生了
无论何时调用一个函数,程序都会保留少量 space 来保存该函数的信息(space 对于局部变量,return 之后的位置信息函数退出等)。该内存是从称为调用堆栈(或简称为“堆栈”)的区域分配的,并且在函数完成时 returned 到堆栈 运行ning.
堆栈通常具有固定的小尺寸。如果你有一个很长的调用链(通常以数万次调用来衡量),你可以 运行 出栈 space 并且程序将终止并出现称为堆栈溢出的错误。这就是您的程序中发生的事情。
一般来说,如果你有递归(或者在你的情况下,相互递归)函数,你需要确保递归深度不会因为某些定义“太大, ”或者这种事情可能会发生。在某些特殊情况下,某些编译器可以识别您正在编写递归代码并将其转换为不分配多个堆栈帧的代码(有关更多详细信息,请参阅“尾调用消除”),但这是例外而不是规则。
好的,因为这是 Windows 10 上的 gcc,请看一下 goodbolt
在没有启用任何优化的情况下,两个函数都被显式调用。
b():
push rbp
mov rbp, rsp
call foo()
call a()
nop
pop rbp
ret
a():
push rbp
mov rbp, rsp
call b()
nop
pop rbp
ret
正如其他答案指出的那样,每次调用都会在堆栈信息中留下如何返回调用函数的函数的信息。
现在因为函数 never return 这个信息永远不会从堆栈中删除,而是不断添加。结果,您得到了堆栈溢出,在 Windows 上由值 0xC00000FD
.
现在,如果您启用优化 (-O2
),编译器能够识别出这是无限循环(使用称为尾递归的技术)。
b():
sub rsp, 8
.L2:
call foo()
jmp .L2
a():
sub rsp, 8
.L6:
call foo()
jmp .L6
因此,启用优化后,您将获得预期的无限循环。