2016-04-06 5 views
1

私は次のようなC++プログラムを用意しています。ここで関数はローカル変数への参照を返します。スタックに正確に何が起こるかを一歩一歩見せてくれますか?このC++プログラムでスタックはどのように段階的に変更されますか?

#include<stdio.h> 

double& init_pi() 
{ 
    double pi = 3.14; 
    return pi; 
} 

double circumference(double r, double& pi) 
{ 
    printf("%lf\n", pi); 
    return 2*r*pi; 
} 

int main() 
{ 
    printf("%lf\n,", circumference(2, init_pi())); 
    return 0; 
} 

ありがとうございました。

+0

コンピュータがこの手順をステップごとにどのように計算するのか? – theblindprophet

+0

はい。私は、このコードは正しくないと分かっていますが、なぜそうではないのか一般的な考え方を持っていますが、スタックの仕組みとそのコードがどのように問題を引き起こすかを完全に理解するために、 –

+1

あなたは自分でデバッグします。 –

答えて

3

普遍的な信念とは対照的に、C++標準ではスタックという概念は決して言及されていません。 (std :: stackクラス以外のテンプレートはここでは意味しません)。

この標準では、機能、制御の流れ、ローカルオブジェクト、ヒープオブジェクト、および静的オブジェクトに関して言及しています。

スタックを持たないアーキテクチャ(私がティーンエージャーだったときに私が使用していた古いTMS 9900シリーズのチップ)には、C++コンパイラを書くことは全く可能です。

Zアーキテクチャ用のYオプションを使用して、Xコンパイラでコンパイルするとき、このC++プログラムにステップすることにより、スタック変更ステップをどのよう

:あなたの質問は、より良いよう

を置くかもしれませんか?真実の答が(gccのために、-Sオプションでコンパイル)リストのみデバッガやアセンブラで横たわるため

、あなたが最適化して、このプログラムをコンパイルする場合、ノーがあるでしょうスタックの動きは全くありません。フロー全体がインライン展開されます。

には、例えば、-O2とGCC 5.3を使用すると、ローカル変数への参照を返すことによって未定義の動作を導入しているため、コンパイラはそれが好きで何かをすることが許可されていること(下記参照)

注次のコードを生成します。この場合、あなたのプログラムは何もしないと決めました。 mainは単にゼロを返します。

アセンブラ出力:

init_pi(): 
     xorl %eax, %eax 
     ret 
.LC1: 
     .string "%lf\n" 
circumference(double, double&): 
     pushq %rbx 
     movl $1, %eax 
     movq %rdi, %rbx 
     subq $16, %rsp 
     movsd %xmm0, 8(%rsp) 
     movsd (%rdi), %xmm0 
     movl $.LC1, %edi 
     call printf 
     movsd 8(%rsp), %xmm1 
     movsd (%rbx), %xmm0 
     addq $16, %rsp 
     addsd %xmm1, %xmm1 
     popq %rbx 
     mulsd %xmm1, %xmm0 
     ret 
main: 
     movsd 0, %xmm0 
     ud2 

コンパイラ警告:我々は警告とその後のエラーを修正した場合、我々はこの取得

/tmp/gcc-explorer-compiler11636-75-1libuwy/example.cpp: In function 'double& init_pi()': 
5 : warning: reference to local variable 'pi' returned [-Wreturn-local-addr] 
double pi = 3.14; 
^ 
Compiled ok 

:再び

init_pi(): 
     movsd .LC0(%rip), %xmm0 
     ret 
.LC2: 
     .string "%lf\n" 
circumference(double, double): 
     subq $24, %rsp 
     movl $.LC2, %edi 
     movl $1, %eax 
     movsd %xmm0, 8(%rsp) 
     movapd %xmm1, %xmm0 
     movsd %xmm1, (%rsp) 
     call printf 
     movsd 8(%rsp), %xmm2 
     movsd (%rsp), %xmm1 
     addq $24, %rsp 
     addsd %xmm2, %xmm2 
     movapd %xmm2, %xmm0 
     mulsd %xmm1, %xmm0 
     ret 
.LC5: 
     .string "%lf\n," 
main: 
     subq $8, %rsp 
     movl $.LC2, %edi 
     movl $1, %eax 
     movsd .LC0(%rip), %xmm0 
     call printf 
     movsd .LC4(%rip), %xmm0 
     movl $.LC5, %edi 
     movl $1, %eax 
     call printf 
     xorl %eax, %eax 
     addq $8, %rsp 
     ret 
.LC0: 
     .long 1374389535 
     .long 1074339512 
.LC4: 
     .long 1374389535 
     .long 1076436664 

を、あなたがいることがわかりますmainは完全にインライン化されています。何もスタックの使用はありません(printfの呼び出し中以外)

関連する問題