c言語でスタック領域の使われ方について質問です。
メイン関数{
if(true){
} //if文終わり
サブ関数1()
サブ関数2()
}
このときのスタックのプッシュ、ポップの行われ方について教えてください。
自分の予想では以下のようになると考えていますが自信が全くありません・・・・
1 まずメイン関数をプッシュ
2 if文をプッシュ ??? <???が特に自信ないです。
3 if文をポップ ???
4 サブ関数1をプッシュ
5 サブ関数1をポップ ???
6 サブ関数2をプッシュ
7 サブ関数2をポップ ???
8 メイン関数をポップ
もし知っていたら教えてください。
よろしくお願いします。
No.5ベストアンサー
- 回答日時:
>if(x){
>int y=1;
>}
>y=4;
>こうしたときエラーが出る理由はどうしてなのでしょうか?
スコープの関係です。
「int y」はif文の{}の中で宣言されている為、{}内でしか使用できません。
上記であれば、if文よりも前({}の外)に定義している必要があります。
「エラーが出た」で終わらず、「エラーメッセージの内容」を理解することも行ってください。
回答ありがとうございます。。
>>スコープの関係です。
>>「int y」はif文の{}の中で宣言されている為、{}内でしか使用できません。
"variableの存在範囲外でそれを使おうとしただけ”であって、
別にpopされたから使えないというわけではないんですね。
とても助かりました。
それと、質問の内容がとても初歩的でかつ勘違いしたものになっていて、
本当に申し訳ないです。。
それでも、一応、私が知りたかったことは理解できたので、
回答してくださった皆さん本当にありがとうございます。
No.7
- 回答日時:
>if(x){
>int y=1;
>}
>y=4;
>こうしたときエラーが出る理由はどうしてなのでしょうか?
コンパイラの動作と実行時のスタック動作をゴチャ混ぜに考えるとそうなりますね。
ともかくこれはC言語の文法の問題です。変数のスコープと言って、ブロック({}←これ)内で宣言された変数の寿命はブロック外に出るまでと取り決められているためです。
{
int y=1; ← ここでyが有効になる。
} ← ここでyが無効になる。
実際問題、コンパイラの実装の問題なので変数yのメモリ実体は消えていないかも知れませんが、C言語の規約でそうなっている以上はエラーです。
No.6
- 回答日時:
処理系を特定せずにスタックといわれても困ります。
それに、予想を見ると、プログラムの動作ではなく構文解析時の動作のようにも見えます。
何が知りたいのか、そして想定している処理系は何か、あわせて補足してください。
No.4
- 回答日時:
#2の補足についてです
エラーってのは y が定義されてないってエラーじゃないですか?
原因は y のスコープに問題があるからです
そのソースプログラムでは yがif文の条件に引っかかったとき
しか定義されません
コード的に見れば絶対ifの条件に引っかかりますが
コンパイラは其処までのチェックは行いません
if文の前に int y; を書いてみてください
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、標準形式ではこの順で行われます。
これで分かるように、関数のパラメータはスタックに呼び出し元変数のコピーが作られ、それが
渡されています。関数側でパラメータ内容を変更しても、それはコピーをイジッているのであって、
呼び出し側の変数自体は何も変化しません。
No.2
- 回答日時:
if分単体でPush/Popされることはありません
#1さん書かれたURL見た方が分かりやすいと思いますが
基本的にPush/Pop(スタック)が使われるのは関数呼び出し時と
その引数の受け渡しのときのみとなります
また関数呼び出しのときにスタックに格納されるのは
その関数ではなく戻りアドレスとなるメイン関数(呼び出し元)の
アドレスとなります
また関数側では自分で使うレジストリなどを関数開始時に
Pushして関数終了時にPopします
スタックされる順番などは呼び出し規約によって異なってきますし
必ずしもスタックが使われるわけでもありません
(場合によってはレジスタ渡しで終わることもあります)
アセンブラコード自分で書かないのであればそこらへんは
コンパイラが自動でやってくれますので
コンパイラがどのようにアセンブラコードに変換しているか
見てみるのが勉強になるでしょう
自前でアセンブラコード書くのであれば気をつけないと
簡単にアプリケーションが暴走します
この回答への補足
早速の回答ありがとうございます。
やはり、大きな勘違いをしていたみたいです。。。
(まだ完全に理解できてません)
>>if分単体でPush/Popされることはありません
これについて質問があるのですが、
int x=1;
if(x){
int y=1;
}
y=4;
こうしたときエラーが出る理由はどうしてなのでしょうか?
エラーが出たので、
ifもpush/popされるのではないかと考えてしまいました・・・。
もし、この理由を知っているかたがいたら、教えてください。
よろしくお願いします。
No.1
- 回答日時:
C言語をアセンブルしたときにどうなるか、ということでしょうか?
C言語をアセンブルした時にpushが使われる代表的な例としては関数の呼び出し時に引数がpushされるとかでしょうかね(ただし、呼び出し規約によって変わるので一概にはなんとも…)。
http://ray.sakura.ne.jp/asm/9.html
私も大して詳しくはないので、あとは専門家にお任せします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 中古パソコン ツールをずっと起動させておくだけのPC 2 2022/06/10 02:10
- Excel(エクセル) エクセル if関数 4 2023/04/27 11:35
- その他(パソコン・周辺機器) 2つのPCを行き来する 2 2022/06/15 01:59
- Excel(エクセル) ExcelのIF関数について 4 2023/05/24 12:54
- Excel(エクセル) スプレットシートの関数 3 2023/04/07 11:49
- LTE microsoft authenticatorアプリ 3 2023/08/05 07:31
- Excel(エクセル) エクセル関数で教えて頂きたいです 3 2023/07/24 14:10
- Excel(エクセル) エクセル 関数について質問です。 2 2022/10/03 11:14
- Excel(エクセル) 関数式を教えてください。 AとBのセルがあり、Aのセルに値がある場合はCのセルへ1と表示。 AとBの 5 2022/03/23 14:38
- Excel(エクセル) If関数に関する質問です。(再掲) 3 2022/10/01 20:51
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エラー?メッセージ
-
最大スタックサイズを大きくす...
-
VB.netでDLLを読み込んで実行す...
-
VC++6.0 Stack Overflow !!
-
printf / sprintf のスタック消...
-
CASLとCASL2の違いについて
-
ubuntuで デイスク/deb/loopと...
-
命令口調について
-
パソコンでインターネット接続...
-
ライン数とステップ数の違いに...
-
hdmiはパラレル?シリアル?
-
Macと iPadの違いについて 今現...
-
同じサブネットに属するIPアドレス
-
プログラムの規模を表す単位「k...
-
ホストアドレスの0とは
-
Native VLANの変更
-
TCPではなく、UDPが音声や動画...
-
ステップカウントツールが作成...
-
社内LANのネットワークトラフィ...
-
ミキサの原理
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VB.netでDLLを読み込んで実行す...
-
最大スタックサイズを大きくす...
-
エラー?メッセージ
-
Ethernetヘッダの取得 NDIS
-
GCCで関数の引数が渡らない
-
printf / sprintf のスタック消...
-
スタックフレームの消滅
-
H8マイコン スタック領域に...
-
pthreadのスタックサイズ設定取...
-
_CRTIMPの意味は?
-
スタックを用いて整数配列を入...
-
再帰処理を非再帰処理に書き換...
-
VC++でプログラムから現在のス...
-
cloneのスタック管理
-
マス目上の移動のアルゴリズム
-
gccでスタックサイズを変更する...
-
OCXからのコールバックを繰り返...
-
コンパイラオプション
-
VC++6.0 Stack Overflow !!
-
スタック領域変更
おすすめ情報