coutとprintfから関数のパラメータ伝達過程の検討
2750 ワード
coutとprintfから関数のパラメータ伝達過程の検討
コードを見てみましょう
出力結果は何だと思いますかupdate():1 i:1?間違っています.正しい出力は
なぜそうなるのか、まず実験康をしましょう.
その出力結果は
printfだけがそうですか?いいえ、可変パラメータの印刷関数にはこのような特性があります.coutをテストして検証してみましょう.
出力結果は次のとおりです.
なぜそうなるのか、cとc++の関数パラメータに関するプロセスを話さなければなりません.
アセンブリ内の関数パラメータは、最後のパラメータから最初のパラメータまでそれぞれスタックに入力されます.このように、関数がパラメータを取るとき、popが出る順序は1-nです.
したがって、
以上は理論にすぎず,実際の環境ではx 86,x 64,32ビット,16ビットマシンによって,それらの具体的なパラメータ伝達方式はやや異なる:)
x 64の次の文のアセンブリコードを見てみましょう
X 64の下では、レジスタパラメータである.最初の4つのパラメータはそれぞれrcx rdx r 8 r 9でパラメータを伝達する.余計なスタックを通って参を伝える.右から左へスタックに入ります.
上記のコードではフォーマット文字列がrcx(最後の付与)にあり、update()はedx、2番目の付与値を返します.i r 8における最初の付与.
しかし、
プロシージャは少し変化しますが、最後の結果は、アセンブリ内の関数パラメータと最後のパラメータから最初のパラメータにそれぞれスタックされます.
最後のお題ですね//
しゅつりょくを求める
答えと解析
コードを見てみましょう
#include
int i=0;
int update(){i++;return i;}
int main()
{
printf("update():%d i:%d
",update(),i);
return 0;
}
出力結果は何だと思いますかupdate():1 i:1?間違っています.正しい出力は
update():1 i:0
です.なぜそうなるのか、まず実験康をしましょう.
#include
#include
#include
using namespace std;
int i=0;
int update(){i++;return i;};
int main()
{
printf("----------------------------test printf----------------------------
");
printf("before:%d
",i);
printf("update():%d i:%d
",update(),i);
printf("later:%d
",i);
printf("before:%d
",i);
printf("i:%d update():%d
",i,update());
printf("later:%d
",i);
printf("update1:%d update2:%d update3:%d",update(),update(),update());
}
その出力結果は
----------------------------test printf----------------------------
before:0
update():1 i:0
later:1
before:1
i:2 update():2
later:2
update1:5 update2:4 update3:3
printfだけがそうですか?いいえ、可変パラメータの印刷関数にはこのような特性があります.coutをテストして検証してみましょう.
#include
#include
#include
using namespace std;
int i=0;
int update(){i++;return i;};
int main()
{
cout<
出力結果は次のとおりです.
---------------------------- test cout ----------------------------
before:0
update():1 i:0
later:1
before:1
i:2 update():2
later:2
update1:5 update2:4 update3:3
なぜそうなるのか、cとc++の関数パラメータに関するプロセスを話さなければなりません.
アセンブリ内の関数パラメータは、最後のパラメータから最初のパラメータまでそれぞれスタックに入力されます.このように、関数がパラメータを取るとき、popが出る順序は1-nです.
したがって、
printf("update():%d i:%d
",update(),i);
では、関数はiを先に圧入し、update()を実行し、その戻り値をスタックに圧入する.以上は理論にすぎず,実際の環境ではx 86,x 64,32ビット,16ビットマシンによって,それらの具体的なパラメータ伝達方式はやや異なる:)
x 64の次の文のアセンブリコードを見てみましょう
mov ebx, cs:i
call _Z6updatev ; update(void)
mov r8d, ebx
mov edx, eax
lea rcx, aUpdateDID ; "update():%d i:%d
"
call _ZL6printfPKcz ; printf(char const*,...)
X 64の下では、レジスタパラメータである.最初の4つのパラメータはそれぞれrcx rdx r 8 r 9でパラメータを伝達する.余計なスタックを通って参を伝える.右から左へスタックに入ります.
上記のコードではフォーマット文字列がrcx(最後の付与)にあり、update()はedx、2番目の付与値を返します.i r 8における最初の付与.
しかし、
mov ebx, cs:i
プログラムは、iの値をebxに移動し、update関数を呼び出し、戻り値のあるレジスタeaxをedxに移動するのを見ることができます.プロシージャは少し変化しますが、最後の結果は、アセンブリ内の関数パラメータと最後のパラメータから最初のパラメータにそれぞれスタックされます.
最後のお題ですね//
#include
int main()
{
long long a = 1, b = 2, c = 3;
printf("%d %d %d
", a,b,c);
return 0;
}
しゅつりょくを求める
答えと解析