0

main()内部main()で 10 回再帰的に呼び出しています。(bt/backtrace)を使用してデバッグしているときgdbに、 の複数のフレームが表示されませんmain()。なんで?

#include<stdio.h>

int main(){

     static int i;
     int num=100;

     if(i>10)
       return 0;
     else {
       i++;
       num++;
       main();
       printf("\n%d",num); 
     }
 }
4

3 に答える 3

4

これは の文書化された動作でありgdb(想定されている) 構成可能です。

gcc 4.7.2( )を使用してコードをコンパイルすると-O3、次のアセンブリが得られます。

_main:
LFB1:
        movl    _i.2134(%rip), %eax
        cmpl    $10, %eax
        jle     L6
        xorl    %eax, %eax
        ret
L6:
        addl    $1, %eax
        pushq   %rdx
LCFI0:
        movl    %eax, _i.2134(%rip)
        xorl    %eax, %eax
        call    _main                    ; <=== recursive call
        popq    %rcx
LCFI1:
        movl    $101, %esi
        xorl    %eax, %eax
        leaq    LC0(%rip), %rdi
        jmp     _printf
LFE1:

これは、再帰呼び出しが最適化されているという仮説に反論します。

ここで、バイナリを にロードしgdbてブレークポイントを設定するとmain()、繰り返しヒットします。レジスタを調べる%rspと、呼び出しごとにデクリメントされているため、それぞれに関連付けられたスタック フレームが明確に存在しますmain()

それにもかかわらず、bt単一のフレームのみを表示します。

(gdb) bt
#0  0x0000000100000f50 in main ()

(この場合、1main()つだけではなく 3 つのフレームがあることがわかっています。)

したがって、これはそれ自体に何らかの関係があると結論付けていgdbます。

さらに調査すると、この動作が文書化されていることが判明しました。

ほとんどのプログラムには、標準のユーザー エントリ ポイントがあります。これは、システム ライブラリとスタートアップ コードがユーザー コードに移行する場所です。C の場合、これはmain. は、バックトレースでエントリ関数をgdb見つけると、バックトレースを終了し、高度にシステム固有の (そして一般的には興味のない) コードへのトレースを回避します。

で次を設定するとgdb

set backtrace past-main on
set backtrace past-entry on

main()2 つのフレームが表示され始めます。どういうわけか、それはまだ深く進んでいません。

于 2012-12-19T10:25:30.120 に答える
2

あなたの質問は、あなたがそのために使用するという事実とは何の関係もありませんmain

最後にコメントで示したい単純な再帰プログラムは、再帰をまったく行わないことで、コンパイラーによって簡単に最適化できます。あなたの場合、定義済みの再帰の深さが であるため、通常よりもさらに単純です10。これは、コンパイラによって静的コードに簡単に展開できます。

于 2012-12-19T10:09:06.957 に答える
1
Here is the Answer for my own Question.
(gdb) set backtrace past-main on
(gdb) b main
Breakpoint 1 at 0x4004b0: file recursion.c, line 5.
(gdb) run
Starting program: /nobackup/arjprasa/C/gdb/a.out

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#3  0x000000000040041a in _start ()
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000000004004df in main () at recursion.c:12
#3  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#4  0x000000000040041a in _start ()
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000000004004df in main () at recursion.c:12
#3  0x00000000004004df in main () at recursion.c:12
#4  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#5  0x000000000040041a in _start ()
(gdb)
于 2012-12-19T12:08:34.810 に答える