用C无限递归 [英] Infinite recursion in C

查看:152
本文介绍了用C无限递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到与无限递归C程序:

  INT的main(){    主要();    返回0;
}

为什么会产生这样的结果在一个堆栈溢出。我知道这会导致用C未定义行为++从下列线这是无限递归UB?(并将其作为边节点的一项,不能叫的main()在C ++中)。然而,Valgrind的告诉我,这将导致堆栈溢出:

 螺纹1堆栈溢出:不能成长栈0x7fe801ff8

,最后在程序结束由于分段错误:

  == == 2907与处理信号11的默认操作终止(SIGSEGV)
== == 2907地址0x7FE801FF0没有映射区域内访问

在C这也是未定义的行为,还是应该这真的导致堆栈溢出,然后为什么这导致堆栈溢出?

修改

1,我想知道的是无限递归允许使用C?结果
二要这导致堆栈溢出? (已经被充分解答)


解决方案

当你调用一个函数,参数被压入堆栈,这意味着对堆栈段数据被分配上。当函数被调用,返回ADRESS也压入堆栈,由CPU,因此它知道在哪里可以返回。

在您的例子的情况下,这意味着,没有参数的使用,从而使被压的唯一的事情就是返回ADRESS,这是相当小(在X86-32 architexture 4字节),另外还通过StackFrame调整这需要另外四个字节在此架构。

从这个如下,一旦堆栈段用完后,该功能不能被称为aynmore和异常引发的操作系统。现在有可能发生两件事情。无论是操作系统异常转发回您的应用程序,你将看到堆栈溢出。或操作系统可以尝试分配额外的空间为堆栈segemnt,达到了定义的限制,在这之后,应用程序将看到的堆栈溢出。

所以这code(我把它改名为infinite_recursion()作为主()不能被称为)...

  INT inifinite_recursion(无效)
{
    inifinite_recursion();
    返回0;
}

...看起来是这样的:

  _inifinite_recursion:
    推EBP;栈上的4个字节
    MOV EBP,ESP    调用_inifinite_recursion;栈上另外4个字节
    MOV EAX,0;这将永远不会被执行。    流行EBP
    RET

更新

至于标准C99定义递归,最好的我发现迄今是第6.5.2.2第11段:


  

    

递归函数调用应允许,直接和间接地通过的其他功能的任何链。


  

当然,这并没有回答是否定义为当堆栈溢出时会发生什么。但是至少它可以让递归调用,虽然这是明确用C ++禁止(节3.6.1第3和第5.2.2节第9段)。

Given the C program with infinite recursion:

int main() {

    main();

    return 0;
}

Why would this result in a stack overflow. I know this results in undefined behaviour in C++ from the following thread Is this infinite recursion UB? (and as side node one can't call main() in C++). However, valgrind tells me this leads to a stack overflow:

Stack overflow in thread 1: can't grow stack to 0x7fe801ff8

and then finally the program ends due to a segmentation error:

==2907== Process terminating with default action of signal 11 (SIGSEGV)
==2907==  Access not within mapped region at address 0x7FE801FF0

Is this also undefined behavior in C, or should this really lead to a stack overflow and then why does this result in a stack overflow?

edit

1 I would like to know is infinite recursion allowed in C?
2 Should this result in a stack overflow? (has been sufficiently answered)

解决方案

Whenever you call a function, the arguments are pushed on the stack, which means that data on the stack segment is "allocated". When the function is called, the return adress is also pushed on the stack, by the CPU, so it knows where to return to.

In your example case this means, that no arguments are used, so the only thing that is pushed is the return adress, which is rather small (4 bytes on x86-32 architexture), and additionally the stackframe is adjusted which takes another four bytes on this architecture.

From this is follows that, once the stack segment is exhausted, the function can not be called aynmore and an exception is raised to the OS. Now there can happen two things. Either the OS forwards the exception back to your application which you will see as stack overflow. Or the OS can try to allocate additional space for the stack segemnt, up to a defined limit, after which the application will see the stack overflow.

So this code (I renamed it to infinite_recursion() as main() can not be called) ...

int inifinite_recursion(void)
{
    inifinite_recursion();
    return 0;
}

... looks like this:

_inifinite_recursion:
    push    ebp                    ; 4 bytes on the stack
    mov ebp, esp

    call    _inifinite_recursion   ; another 4 bytes on the stack
    mov eax, 0                 ; this will never be executed.

    pop ebp
    ret 

UPDATE

Regarding the standard C99 for defining recursion, the best I found so far is in Section 6.5.2.2 Paragraph 11:

Recursive function calls shall be permitted, both directly and indirectly through any chain of other functions.

Of course this doesn't answer whether it is defined what happens when the stack overflows. However at least it allows main to be called recursively, while this is explicitly forbidden in C++ (Section 3.6.1 Paragraph 3 and Section 5.2.2 Paragraph 9).

这篇关于用C无限递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆