• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:c言語でスタック領域の使われ方について)

c言語のスタック領域の使われ方について

このQ&Aのポイント
  • c言語でのスタック領域の使われ方について質問です。
  • メイン関数やサブ関数のスタックへのプッシュとポップの順序を教えてください。
  • 具体的なコード例を挙げながら教えていただけると助かります。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

>if(x){ >int y=1; >} >y=4; >こうしたときエラーが出る理由はどうしてなのでしょうか? スコープの関係です。 「int y」はif文の{}の中で宣言されている為、{}内でしか使用できません。 上記であれば、if文よりも前({}の外)に定義している必要があります。 「エラーが出た」で終わらず、「エラーメッセージの内容」を理解することも行ってください。

2009googoo
質問者

お礼

回答ありがとうございます。。 >>スコープの関係です。 >>「int y」はif文の{}の中で宣言されている為、{}内でしか使用できません。 "variableの存在範囲外でそれを使おうとしただけ”であって、 別にpopされたから使えないというわけではないんですね。 とても助かりました。 それと、質問の内容がとても初歩的でかつ勘違いしたものになっていて、 本当に申し訳ないです。。 それでも、一応、私が知りたかったことは理解できたので、 回答してくださった皆さん本当にありがとうございます。

その他の回答 (6)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.7

>if(x){ >int y=1; >} >y=4; >こうしたときエラーが出る理由はどうしてなのでしょうか? コンパイラの動作と実行時のスタック動作をゴチャ混ぜに考えるとそうなりますね。 ともかくこれはC言語の文法の問題です。変数のスコープと言って、ブロック({}←これ)内で宣言された変数の寿命はブロック外に出るまでと取り決められているためです。 { int y=1; ← ここでyが有効になる。 } ← ここでyが無効になる。 実際問題、コンパイラの実装の問題なので変数yのメモリ実体は消えていないかも知れませんが、C言語の規約でそうなっている以上はエラーです。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.6

処理系を特定せずにスタックといわれても困ります。 それに、予想を見ると、プログラムの動作ではなく構文解析時の動作のようにも見えます。 何が知りたいのか、そして想定している処理系は何か、あわせて補足してください。

  • koi1234
  • ベストアンサー率53% (1866/3459)
回答No.4

#2の補足についてです エラーってのは y が定義されてないってエラーじゃないですか? 原因は y のスコープに問題があるからです そのソースプログラムでは yがif文の条件に引っかかったとき しか定義されません コード的に見れば絶対ifの条件に引っかかりますが コンパイラは其処までのチェックは行いません if文の前に int y; を書いてみてください

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

スタックがメモリ領域であることはご存知ですか? プッシュがメモリへの登録、ポップがメモリからの取り出しであることを理解していますか? メモリに登録したり、取り出したりする理由は何か分かっていますか? >if文をプッシュ/ポップ  if分は条件を判断して分岐したり、しなかったりする制御文です。何をメモリに記録するんですか?  必要ないですね。よって、「if文をプッシュ/ポップ」などと今後は言わないようにしましょう。 >サブ関数1をプッシュ/ポップ  意味不明。但し、関数を呼び出す場合、その関数が終わる時に帰り先が分からないと困るので、  呼び出し側(メイン)から見て、関数の次の命令のアドレスをスタックにプッシュします。  呼び出される側(関数の方)はreturnする時にスタックから帰り先アドレスを取り出し、そこに  制御を移します。つまり、帰り先アドレスをプッシュ/ポップするのです。  尚、関数のパラメータもスタックにプッシュされます。このデータはポップされません。関数から  帰る時に、呼び出し側で始末する(PASCAL方式)か、呼び出し元で始末(標準)されます。 自動変数(関数の中で特に記憶域クラスを指定しない変数)はスタック上に領域が取られます。 勿論、帰り先アドレスを壊さないように確保されますが、ポインタや配列のインデックスを間違うと、 これらの領域が破壊され、プログラムが「暴走」することになります。また、関数のパラメータの 後始末は既に述べたように二通りあるので、呼び出し元と関数側で方式が異なると、スタックが ズレてやはり「暴走」することになります。スタックの使用例は以下の通りです。 main() {    関数(long P1,long P2)    ★    次の命令 } (1)P2をスタックにプッシュ (2)P1をスタックにプッシュ (3)「★」のアドレスをスタックにプシュ (4)「関数」に制御を移す(分岐命令) (5)「★」P1,P2を破棄するためSPに8を加算して始末する (6)次の命令が実行される (3)(4)は実際には1命令(動作は2ステップ)です。 ★は標準の場合の後始末で、関数がPASCAL方式の場合は生成されないコードです。 尚、CPU、関数形式によってはP1、P2のスタックへの積み込み方が逆の場合もありますが、 後退法のCPU、標準形式ではこの順で行われます。 これで分かるように、関数のパラメータはスタックに呼び出し元変数のコピーが作られ、それが 渡されています。関数側でパラメータ内容を変更しても、それはコピーをイジッているのであって、 呼び出し側の変数自体は何も変化しません。

  • koi1234
  • ベストアンサー率53% (1866/3459)
回答No.2

if分単体でPush/Popされることはありません #1さん書かれたURL見た方が分かりやすいと思いますが 基本的にPush/Pop(スタック)が使われるのは関数呼び出し時と その引数の受け渡しのときのみとなります また関数呼び出しのときにスタックに格納されるのは その関数ではなく戻りアドレスとなるメイン関数(呼び出し元)の アドレスとなります また関数側では自分で使うレジストリなどを関数開始時に Pushして関数終了時にPopします スタックされる順番などは呼び出し規約によって異なってきますし 必ずしもスタックが使われるわけでもありません (場合によってはレジスタ渡しで終わることもあります) アセンブラコード自分で書かないのであればそこらへんは コンパイラが自動でやってくれますので コンパイラがどのようにアセンブラコードに変換しているか 見てみるのが勉強になるでしょう 自前でアセンブラコード書くのであれば気をつけないと 簡単にアプリケーションが暴走します

2009googoo
質問者

補足

早速の回答ありがとうございます。 やはり、大きな勘違いをしていたみたいです。。。 (まだ完全に理解できてません) >>if分単体でPush/Popされることはありません これについて質問があるのですが、 int x=1; if(x){ int y=1; } y=4; こうしたときエラーが出る理由はどうしてなのでしょうか? エラーが出たので、 ifもpush/popされるのではないかと考えてしまいました・・・。 もし、この理由を知っているかたがいたら、教えてください。 よろしくお願いします。

  • LOHA
  • ベストアンサー率52% (203/388)
回答No.1

C言語をアセンブルしたときにどうなるか、ということでしょうか? C言語をアセンブルした時にpushが使われる代表的な例としては関数の呼び出し時に引数がpushされるとかでしょうかね(ただし、呼び出し規約によって変わるので一概にはなんとも…)。 http://ray.sakura.ne.jp/asm/9.html 私も大して詳しくはないので、あとは専門家にお任せします。

関連するQ&A

専門家に質問してみよう