printfであそぼう(2)
最近は全然何も作ってないんですが、本読んでてprintfの動作について思い当たる節があったんで、ちょろーんとメモ。
スタックの積まれ方 |--------|--------|--------|--------| |--------|------〜 | | | | | → | | |ローカル| | 直前の |リターン| 積 |ローカル| | 変数 | 引数 |フレーム|アドレス| む | 変数 | 引数〜 | | | | | → | | |--------|--------|--------|--------| |--------|------〜 ←高位アドレス 下位アドレス→
スタックには、関数が呼ばれるたびにデータが高位アドレスから下位アドレスへと乗せられていくんだったよね。*1
上図はスタックの乗り方。
で、前はすっかり忘れてたけどprintfも関数なのよね。だからprintfを呼び出せば呼び出し元の関数がスタックに乗る。
そして配列は要素が下位から上位に並ぶ。ポインタ演算も同様。
前回のprintfの出力は四個目が引数になっていたので、それに対応をつけてみる。
funcall(x)からprintf("%d %d %d %d %d %d %d %d")を呼び出したときの出力は、
一個目の%d : printf()用のスタック部分の最高位(無意味な値?)
二個目の%d : funcall(x)のリターンアドレス
三個目の%d : funcall(x)の直前のフレーム
四個目の%d : funcall(x)の引数 x
五個目の%d : funcall(x)のローカル変数用(無意味な値)
六個目の%d : funcall(x+1)のリターンアドレス
七個目の%d : funcall(x+1)の直前のフレーム
八個目の%d : funcall(x+1)の引数 x+1
という並びになっていたと考えられる。
これを裏付けるように、三個目の%dの出力結果が、funcallから新たなfuncallを呼び出すたびに16ずつ減っている。スタックは 下位アドレス=数値が低い方 へと伸びていくし、funcall一つのフレームは4Byteが4つのスペースなので、一つのfuncallがスタックに押し込まれた結果だと見れば計算がぴったり合う。
でまあ、printfのポインタは初期状態でどこを指しているかというと、どうやら次のスタック位置を指しているようだ。
なんか意味があるんだろうか。よく分からないが、メモなので今日はさよなら。
*1:っていうのは機種依存か