08/06/15 13:52:30
899さんの考えではint型変数a,b,cを含んだ構造体を一度に
PUSHしたから、取り出すのも同時にPOPできる・・・だから
変数を使用する順番は関係ないのだ、とこういう理屈でしょうか?
そうだとしたら何かおかしくありませんか?
ヒントですが898の日本語の文章はわざと誤解を生じるような
表現が使われています。スタックの本質は、PUSHにしろPOPに
しろ、それは必ずスタックポインタの遷移を伴う操作でなければ
ならないということです。POPするということはスタックから
データを取り除く、つまり”そのデータはもう使わないよ”
という意味ですよね? さて、898で私が書いた"値を参照"
する行為は果たしてPOPでしょうか?
ここをじっくり考えると何が問題だったか見えてくると
思いますよ。
901:デフォルトの名無しさん
08/06/15 14:04:38
何かおかしくありませんか?と書いてどこがおかしいのか指摘しないのはどうよwww
ともあれ、関数呼びだしに使われるスタックとデータ構造の議論でいうスタックは似ているが別のものってことで
902:デフォルトの名無しさん
08/06/15 14:06:55
寧ろ、struct {int a, b;}をスタックから取り出していると捉えてもいいかもしれない。
その後の仮引き数やローカル変数がスタックに積まれるかどうかは実装依存だし。
903:デフォルトの名無しさん
08/06/15 14:20:03
スタックといっても色々あって、pushされたら、popするまで
一切アクセスすることが出来ないものもあれば、アクセスでき
るものもある。
Cの関数の引き数用のスタックは、当然アクセスできるタイプが
使われる。問題はスタックポインタをどうやって関数は知らされたか
だが、まぁ隠しグローバル変数(register属性)とでも思って桶
904:898
08/06/15 14:34:42
>>ともあれ、関数呼びだしに使われるスタックとデータ構造の議論でいうスタックは似ているが別のものってことで
こういう中途半端な理屈で自分を納得させて学習を止めてしまうのが
一番良くありません。疑問があれば納得するまで調査するべきです。
私はCを勉強したての頃に前述の疑問を持ちその理由がよく説明
できませんでした。そこで自分なりに調べた結果、出した結論が
以下の答えです。
1)スタックはLIFO(Last In First Out)方式であり
後に入れたデータから先に読みだされる
という記述の”読みだされる”というのがあたかもPOP
をしたかのように誤解を与える記述ですが、実際は内部の
動作としては”値を読みだす(参照する)行為”は”POP操作”
ではありません。スタックポインタが移動してないからです。
(続く)
905:898
08/06/15 14:35:26
898のスタック構造は若干、はしょった部分があり正確には
関数add()内部でのスタック構造はこんな感じになります。
ebpレジスタ
変数 c (ローカル変数)
関数の戻り先アドレス
変数 a
変数 b (最後の引数から積まれる)
(スタック領域の先頭アドレス)
そして関数内部ではesp(スタックポインタ)を一旦ebpレジスタ
に格納したうえで(アセンブラではmov (ebp,esp) )、変数a,変数b
への参照を以下のように行っています。
変数a dword ptr[ebp+12]
変数b dword ptr[ebp+16]
変数c dword ptr[ebp+4]
add()関数内部の処理はこれらをアキュムレータで演算しているに
過ぎません。
(続く)
906:898
08/06/15 14:37:19
関数を抜けるときに初めてPOPが行われます。
1)変数cをPOP
2)POPで呼び出し元に復帰
3)変数aをPOP
4)変数bをPOP
※実際にはPOPを行わずにスタックポインタの値を進める事で
代用する場合が多いです。
結局、関数の中でスタックに積まれた引数やローカル変数の値
を使用することはスタックからそのデータを取り出した(POPした)
わけではないのだから、スタックの定義と全く矛盾しませんよ
ということを言うためにこんなまわりくどい説明をしました。
でも、案外誤解している人って多いかもしれないと思います。
なお、これらは日経BP社の「プログラムはなぜ動くのか」という
本の第10章「アセンブリ言語からプログラムの本当の姿を知る」
を読めば完全に理解できると思います。
(終)
907:898
08/06/15 14:58:50
>>903
ここはCに関するスレッドなので、スタックの概念や実装についても
Cの範疇でのみ回答しております。
908:デフォルトの名無しさん
08/06/15 15:00:23
>>904-906
だから、その話を踏まえて「似ているが別のもの」って言ったんだよ
Cの普通の実装で使われる呼び出しスタックは、配列上に構築したスタックと同じで、
スタックポインタからのオフセットを指定することで任意の要素のO(1)読み書きができるけど、
これは「スタック」というデータ構造が元々持ってる機能ではないってこと
基本的な意味でのスタックでは、値を取り出すにはpopするしかない
そこを混同してると>>898みたいな疑問が生まれる
909:898
08/06/15 15:12:50
あらま、詳しいお方でしたのね。失礼。
910:ebpなんて、極一部のCPUにしかないレジスタ持ち出すなよpgr
08/06/15 15:19:18
つーか、Cの仕様レベルでの話に実装を持ち出す>905はいかがなものかと。
911:898
08/06/15 15:55:18
>>910
正論だ。まったくもって正論だ。
「プログラムはなぜ動くのか」の本にもPentiumなどのx86系
マイクロプロセッサ用アセンブリ言語を対象として解説する
って書いてあった。どんなレジスタが使われるかはコンパイラ
依存だとも・・・。説明不足でした。まあ実装はちょっと置いといた
としても、なぜに「スタック」という名前なのに下のデータにアクセス
できてしまうのかという疑問については解決ってことで...(苦しい)
912:デフォルトの名無しさん
08/06/15 20:44:45
ポーランド記法で計算を行う為のアルゴリズムを教えてください。
913:デフォルトの名無しさん
08/06/16 08:28:06
CPUのスタックはスタックポインタいじればどこでもアクセスできるだろ
引数の渡し方も呼び出し規約で変わる
fastcallだとレジスタ渡しだし
914:デフォルトの名無しさん
08/06/16 17:48:41
C#での質問です。
string[] str = new string[10];
char[,] moji = new char[10,30];
このstrにファイルを読み込んで文字列として格納したものを、
mojiにコピーするにはどうしたら良いのでしょうか?
ToCharArray()を使おうと思ったのですが上手くいかずに困っています。
どなたかご鞭撻の程宜しくお願いします。
915:デフォルトの名無しさん
08/06/16 22:15:25
ここがC#のスレッドに見えたんだろうか。
916:デフォルトの名無しさん
08/06/16 23:37:02
>>915
>>1を見ればC#スレにしか見えないだろ。
>>914
ジャグ配列で良ければ、ToCharArrayが使える。
矩形のchar[,]でないといけないなら、自分でループ回す方法しか俺には思い浮かばない。
char[][] moji = new char[str.Length][]; //別にnew char[10][]でも
for (int i = 0; i < str.Length; i++)
{
moji[i] = str[i].ToCharArray();
}
917:914
08/06/17 09:18:37
>>916さん
わざわざお答え頂きありがとうございます。
なるほど、出来なかった理由は宣言の時点での間違えだったのですね。
大変助かりました。
918:914
08/06/17 17:11:58
連投してすみません;
914の者ですが
配列mojiにstring型の文字列を格納することは出来たのですが、
もう一つmojiと同じ方の多次元配列を用意して、
それにmojiをコピーしたいのですが上手くいきません;
Array.Copyなどを使えば動作はするのですが、配列の中身が変わっておらず
どうすればいいのか分かりません。
度々すみませんが、宜しくお願いします。
919:デフォルトの名無しさん
08/06/17 22:45:18
>>917
いいえ、「間違え」ではありません、「間違い」です。
920:914と918
08/06/18 16:53:48
918のものですが自己解決しました。
お騒がせしてしまい、すみません;
>>919
おぉ、確かに間違えてる;
ご指摘どうも。