スタック領域について

[戻る]
ミミ 2006/01/07(土) 23:48:36
いつもお世話になります。ミミです。
毎回冗長的な質問で申し訳ありません。

WinCE 3.0 環境でのスタック領域は 58KB、
Win2K等のPC環境でのスタック領域は 1MB 程度と認知していますが、
このスタック領域の残容量を取得する方法を探しています。

現在は、このスタック領域をわざとオーバーフローするように細工し、
その結果から導くしかないかと考えていますが、もう少しスマートに残量が
分かるような API 等はありませんでしょうか?

最終的な目標は WinCE 機でのスタック領域残量の取得ですが、
まずは、PCにて意図的にスタックオーバーフローさせ、
指定した値から残りの残量を把握する為のテストプログラムを作ってみました。


<<テストプログラム>>

ダイアログベースでテストプロをつくり、
App::InitInstance()で、Dlgクラスをインスタンス化し(スケルトンで既に生成されています)
さらにOnButton1()内に、大きなサイズのローカル変数(=スタック)を宣言しました。

CHogeDlg::OnButton1(){
   char    sTest[☆];     // 下記参照
   memset(&sTest, 0x00, sizeof(sTest) );
   MessageBox("End of Func.", "", MB_OK);    
}

と記述し、PCにてDebug環境で試してみました。
sTestのサイズ(☆)が、1048576(1024x1024B)と指定した時、
Debug環境だと「c00000fd Stack Overflow」と例外が発生します。
しかしRelease環境だと何もエラーが発生せず処理が続きます。
ですが、偶然動いているだけと思うので非常に危険と考えています。

この☆の値を徐々に減少させ、例外が発生する・しないの境目となった時の☆の値が
残りのスタック領域と認識できますが…非現実的な様な気がします。

テストアプリ作成環境
 Win2000、VC6、MFCを使用したダイアログベースアプリ

Ban 2006/01/08(日) 02:52:10
# お金を出してよければ、動的解析ツールにスタック計測機能もありそうな気がします
が、
# ここでは自作する前提で。

実行パスがプロファイラ(VC6pro以上ならついてるはず)等で判明していれば、
そのときのスタックポインタの値をアセンブラで引っこ抜けば、
大まかな残量は取れるのではないかと思い、ざっと探してみたらこんなスレが。
http://forums.belution.com/ja/vc/000/133/80.shtml

# スタックサイズ(1Mなど)の方は、PE ヘッダに書かれるので、これを読めば取れるは
ず。
# CEは分かりませんが.....。

また、使用スタックサイズは概ね呼び出し関数毎の使用スタックサイズの和なので、
理論値でよければ、使ってみたことはありませんが、
http://www.vector.co.jp/soft/win95/prog/se119765.html?site=n
このあたりのツールで関数毎のスタックサイズを出して、
関数のコールスタックと照らし合わせる(ようなツールを書く)とか。


> ですが、偶然動いているだけと思うので非常に危険と考えています。
御意。

Bosscat 2006/01/08(日) 06:23:29
お疲れ様です。

> WinCE 3.0 環境でのスタック領域は 58KB、
> Win2K等のPC環境でのスタック領域は 1MB 程度と認知していますが、

WinCEは知見がありません。
少なくとも、WinNT,Win2k,WinXPは指定可能です。

この値はリンク時に決まります。
スレッド毎に設定することはできません。(WinNT系)

多分CEも同じでしょう。


スタックのアーキテクチャが大きく違うとは思えないのと、
MSDNを覗いて見た所、利用するAPIは対応している模様なので
そのまま答えてしまいます。


さて、この問題は以下の理解が必要ですが、どうでしょうか?
・論理アドレスの管理され方
  →コミット、リザーブ、等
・スタックの動作
  →主にガードページ
・スレッドコンテキスト
  →論理レジスタ等

以下の話で、詰まる部分があるのならば、
上記単語を頼りに調べて貰えれば良いと思います。

■解析の話
以下に、Win2kのとあるプロセスの論理アドレスの状況を示します。
 独自ツールで引っこ抜いた情報です。

【論理アドレス状況 -- 抜粋】
   BaseAddr   Size       State Type    Acc    Attr
        :
 1: 0x00030000 0x000F9000 RESV   PRI           RW           
 2: 0x00129000 0x00001000 CMIT   PRI    RW  G  RW           
 3: 0x0012A000 0x00006000 CMIT   PRI    RW     RW
        :
【スレッドコンテキスト情報 -- 抜粋】
 TID:0x00000AAC ESP:0x0012FE48     

3行目のブロック内にスタックポインタがあるようです。
(つまりこの領域はスタック)

次にスタックポインタの直上のブロック(2行目)は1ブロックだけ
コミットされています。
これがガードページです。

更にその上に1行目に予約領域(未コミット)があります。

スタックはこの3行で1セットです。
(理由はガードページの仕組みにあります)
 → 3行のブロックの総和は1Mになってますね。

以上、スタックのボトム、トップ、ポインタ、それぞれの位置が判明したので
スタック領域の残量も計算できます。

これで後は、実際の手法の話だけです。


■技術的な手法の話
ここら辺はポインタだけで良いでしょう。

・論理アドレス状況の抜き方
 VirtualQueryを利用します。(winbase.h)

・スレッドコンテキストの抜き方
 自スレッドの情報で良いなら、適当なスタック変数を見るか
  直接レジスタの値を見れば良い。

 別スレッドから抜く場合、
 『toolhelp32』ライブラリを利用します。(WinCE 2.0以降)
  →CreateToolhelp32Snapshot() 等を使う。


以上です、暇があったらまた来ます。

Bosscat 2006/01/08(日) 06:30:36
追記というか修正です。。

> 3: 0x0012A000 0x00006000 CMIT   PRI    RW     RW
> TID:0x00000AAC ESP:0x0012FE48     

ガードページが、スタックポインタの直上に来ていません。
むしろ底ですね・・・

ただ、コレもガードページの仕組みです。
・成長過程のスタックの場合、スタックポインタの直上がガードページです。
・その後、スタックが巻き戻される(衰退する)と
 スタックポインタだけ底に落ちていきます。(今回の例)

ITO 2006/01/08(日) 15:33:27
WinCE用のVisualC++にその手のツールはないんですか?
組み込み用C++言語という位置づけでいいんですよね。
リンクのオプション等にもありそうな気がするのですが。

シャノン 2006/01/08(日) 16:34:51
CE で通用するかどうか分かりませんが、参考になりますか?
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200503/05030004.txt

シャノン 2006/01/08(日) 16:51:27
> スタックはこの3行で1セットです。
> (理由はガードページの仕組みにあります)
>  → 3行のブロックの総和は1Mになってますね。

なるほど。
スタック1MBと言っても、1MB確保されているのではなく予約されているだけで、
ガードページに触っちゃったら例外トラップして確保しているわけですか。面白い。

ミミ 2006/01/09(月) 00:41:24
こんばんは、ミミです。

Ban様、Bosscat様、ITO様、シャノン様、ご返信ありがとうございます。
今回もまたお世話になります。

・・・率直な所、皆様が折角ご指導してくれたにも関わらず、殆ど理解できていません。
自分の技力の無さが思い知らされます。

理解しないうちは手も足も出ませんので、
まず、Bosscat様がご説明してくださいました解説を理解する所から始めてみます。
Ban様とシャノン様がリンクしてくださいましたURL先も調べてみます。
一方で、ITO様のご指摘のあったリンクオプションも調べてみます。

# 個人的には API さえ発行すれば、
# GlobalMemoryStatus() で現在のメモリステータスを取得する方法と同じような感じに
# スタックサイズも取得できるものかと思っていました・・。

シャノン 2006/01/09(月) 20:00:38
> この値はリンク時に決まります。
> スレッド毎に設定することはできません。(WinNT系)

プロセスのメインスレッドはそうですが、CreateThread で作る場合は個別に指定できま
すね。

Ban 2006/01/10(火) 05:13:23
CreateThread で指定するスタックサイズは、
<MSDN>
スタックの初期のコミットサイズを、バイト単位で指定します
</MSDN>
なんですよね。リザーブサイズではなく。
んで、1MBってのは、リザーブの方。

Ban 2006/01/10(火) 05:19:50
追記:原文の方.
<MSDN Thread Stack Size>
To increase the amount of stack space which is to be
initially committed for a thread, specify the value
in the dwStackSize parameter of the CreateThread or CreateRemoteThread function. 
</MSDN>

ahan 2006/01/10(火) 09:43:20
>However, if the initially committed size specified by dwStackSize
>is larger than the default reserve size, the reserve size is
>this new commit size rounded up to the nearest multiple of 1 MB. 

とも書いてありますね。

Ban 2006/01/10(火) 09:54:33
あ、ホントですね。
そうだったのか…orz

PATIO 2006/01/10(火) 10:25:31
基本的にスタックサイズに関しては実行ファイル作成時に決まる物であって
OSの環境による物ではないと思います。
要するにビルド時の設定で決まると考えてよいのではないでしょうか。
PCとCEの規定値の違いは単にリソースがリッチなのかプアなのかと言う条件の違いから
来るものであって、ビルド時の設定によっては変わってくるでしょう。
ただ、スタック領域をあまり大きくしてしまうとプアな環境では動作しないという
事になってしまうでしょうから、あまり頻繁に変えるような設定ではないと思います。
なのでスタックの残り領域を云々するよりもきちんと使用するローカル変数の管理を
行ってスタックを大きく消費するような変数はヒープ領域から取得するように
プログラマ側で使い分けるべきです。もしくは設計時にはじめからきちんと決めます。
変数の管理をきちんとしていれば、通常は規定値のサイズで十分動作すると思います。
規定値のサイズで動かない場合は、むしろ設計とかプログラミング方法に問題があると
考えるべきではないでしょうか。

シャノン 2006/01/10(火) 15:17:24
> あ、ホントですね。
> そうだったのか…orz

#ほ、ほーら、俺の言ったとおりだ(嘘付け
#ごめんなさい間違えてました

ITO 2006/01/13(金) 19:14:32
試しにマップファイルを作ってみました。
結構細かく出力されています。
これならスタック領域も出力してくれてもいいような気がします。

ITO 2006/01/13(金) 19:27:57
追加です。

実際のアドレスは分りませんが、マップファイルだけでも個々の関数のリンク時の
アドレスが見られます。
スタック領域は分らなくても、かなりの情報は得られると思います。

とおりすがり 2006/01/14(土) 01:13:34
あまり調べてないんですが、ビルド時の設定で決まるスタックサイズって
メインスレッドだけじゃないんですかね?
自分で立ち上げたサブスレッドは、指定可能じゃないですか?
指定しなければ、メインスレッドと同じになるでしょうけども。

Ban 2006/01/14(土) 12:11:57
> 試しにマップファイルを作ってみました。
   -- snip --
> これならスタック領域も出力してくれてもいいような気がします。

静的に出力されるマップで、動的なスタックの使用量を得るのは無理でしょう。
# 仮に関数単位での消費スタックサイズがわかったとして、
# いくつの関数呼び出しがネストしてるかなんて実行時にしか特定できないわけで。

> 実際のアドレスは分りませんが、マップファイルだけでも個々の関数のリンク時の
> アドレスが見られます。

それを確認するのがマップの主目的(?)ですから、コードが配置されるアドレスは
確かにわかりますが、実行時の消費スタックサイズを知る助けにはなりません。

> スタック領域は分らなくても、かなりの情報は得られると思います。

ミミさんの目的がデバッグなどなら役に立つかも知れませんが、
使用メモリの確認(組み込みだとありがち)が目的の場合には直接関係してきません。


> 自分で立ち上げたサブスレッドは、指定可能じゃないですか?
> 指定しなければ、メインスレッドと同じになるでしょうけども。

そうですね。可能でした。

その上で、ミミさんが欲しいのは、そこで指定するスタックサイズ自体ではなく、
「今、その中からどれだけ使ってるか/どれだけ残っているか」かと。

シャノン 2006/01/14(土) 18:50:36
>> 自分で立ち上げたサブスレッドは、指定可能じゃないですか?
>> 指定しなければ、メインスレッドと同じになるでしょうけども。

> そうですね。可能でした。

それは

> シャノン 2006/01/09(月) 20:00:38

あたりのことを言っているのでは?

#CreateThread じゃなくて NtCreateThread 使うなら可能かもしれないけど。

ITO 2006/01/14(土) 19:52:20
何か手がかりになりますか?

Windows CE .NET の高度なメモリ管理
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/jpdnce/htm/advmemmgmt.asp

Windows CE Platform Builder Version 3.0 リリース ノート
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/wcelib/htm/relnotes.asp

ミミ 2006/01/17(火) 00:51:34
こんばんは、ミミです。

ahan様、Ban様、PATIO様、シャノン様、とおりすがり様、ITO様
先週の書き込みから、色々とご指導ありがとうございます。

・・皆様の言っておられる事がまだ理解できていません。(冷汗)
Windowsプログラムの基本はもちろん、コンピュータの仕組みや
OS側の知識まで必要なのだなと痛感しております。


>-------------------------------
>PATIO様 2006/01/10(火) 10:25:31
>変数の管理をきちんとしていれば、通常は規定値のサイズで十分動作すると思います。
>規定値のサイズで動かない場合は、むしろ設計とかプログラミング方法に問題があると
>考えるべきではないでしょうか。

ご指導ありがとうございます。
仕事の作業時間の都合上、結局このスレッドの一番上に示した
方法(あまりにも原始的ではありますが)を用いて調査してみました。

以下、要点だけまとめたコードで記述します。

(開発中の)プログラムが実行中の時に、
例えば OnButton1()等のタイミングで残りのスタックサイズがどのくらいか、
(=即ち、どのくらいのローカル変数(スタック確保分)を定義すればスタックオーバーフローに
なるか)
で調べた所、58KBの WinCE 制約上、43KB 程度の値は確保する事ができました。
一方で、スケルトンのみのプログラムでさえも、46KB 程度確保できました。
よって、開発中のプログラムでは 3KB (46-43)程度の消費量と考えています。

ただ、別の OnButton2()のタイミングで実行される関数に於いて、

void CHoge::OnButton2(){
  // ☆
  MY_TABLE  myTbl;          // ★1 MY_TABLEのサイズは分かりやすく10 KBとします。
  myTbl = Func1();
}

MY_TABLE CHoge::Func1(){    // ★2
  return Func2();
}

MY_TABLE CHoge::Func2(){    // ★3
  MY_TABLE  myTbl;          // ★4
  memset(&myTbl, 0x00, sizeof(MY_TABLE) );
  〜ここで、myTblに対して値を設定する処理〜
 return myTbl;
}

という処理が行われています。
この場合に、☆の位置にて、残りのスタック容量が極端に少ないことが確認できました。
OnButton2()が呼ばれてすぐに、例えば 
   MY_TABLE  myDmy;
等と追加するだけで、スタックオーバーフローを再現する事ができます。

関数が関数を呼んでいるので、
インスタンス化している、★1、★4では 10KB ずつスタックに確保されるのは分かります
が、
戻り値として定義しているだけの、★2、★3でもスタック消費されている気がしています。

# 単に私の勉強不足なのかもしれません。C言語の基礎知識でしょうか?
# 戻り値として定義してある関数を呼ぶだけでも、戻り値分のサイズがスタックに確保されるの
でしょうか??

現在、この回避方法として、★1ではローカル変数(スタック)ではなく、メンバ変数(ヒープ)
として確保し、
Func1()、Func2()も MY_TABLE 型のポインタでやりとりしようと考えています。

(↓下に続きます。)

ミミ 2006/01/17(火) 00:51:48
>-------------------------------
>ITO様 2006/01/08(日) 15:33:27
>組み込み用C++言語という位置づけでいいんですよね。
>リンクのオプション等にもありそうな気がするのですが。

はい。組み込み用と言っていいのか分かりませんが、モバイル機を使用しています。
仰るとおり、リンクのオプションに「/stack:0x10000,0x1000」と指定されている箇所があり
ました。

また、マップファイルを作成して検証していただいたとのこと、誠にありがとうございます。
それを作成すれば、何か手がかりがつかめるのですね。
リンクオプションについてと、マップファイルが何なのかから、スタートしてみます。
一方で、MSDNへのリンク、ありがとうございます。

# 難しい内容ばかりで、凹みそうですが、空いた時間でじっくり読んでみます。

>-------------------------------
>Ban様 2006/01/14(土) 12:11:57
>その上で、ミミさんが欲しいのは、そこで指定するスタックサイズ自体ではなく、
>「今、その中からどれだけ使ってるか/どれだけ残っているか」かと。

はい。仰るとおりです。
今回の書き込みの最初に記載したとおり、結局はバグ探しの為にスタックサイズの取得方法を探
していました。
確かにスタックサイズを大きく指定すれば症状を「回避」することはできるのかもしれませんが
問題を「解消」したとは言えないですね。

当方で問題が発覚した時、がむしゃらに試し、メンバ変数化すれば症状は出ないことだけは確認
していました。
もちろん、当時は理由なんてこれっぽちも考えられませんでした。
メンバ変数化して逃げたかったのが本音なのですが、でもじっくり調査しなければ、
今回の件は(スタックオーバーフローするFunc1()、Func2()について)分からなかった訳
で・・・。


以上、走り書き&ご返信してくれた全ての方への返信が出来ないことをお許しください。
とりあえず、スタックオーバーフローが発生してしまう当方の件については、その対処法が見つ
かったので
それで試行してみます。
完全に確認がとれましたら、改めて解決チェックを付けさせて頂きます。

長文失礼しました。

Ban 2006/01/17(火) 01:22:27
> # 単に私の勉強不足なのかもしれません。C言語の基礎知識でしょうか?
> # 戻り値として定義してある関数を呼ぶだけでも、戻り値分のサイズがスタックに確保
されるの
> でしょうか??

確保される可能性があります。
実体を関数から戻そうとしていますが、この際の動作イメージを簡単に書くと、
一度「無名の一時変数」が作られて、それが戻り値を受ける変数にコピーされる感じで
す。
なので、この暗黙の一時変数がスタックに積まれる可能性があるわけです。

ただし「戻り値の最適化」というのが許可されてますので、ただの構造体などで
デストラクタ等の副作用もなければ、コンパイラの最適化によってはこの
一時変数がなくなる *可能性もあります*。
お使いの環境では消えないのでしょう。

PATIO 2006/01/17(火) 13:47:41
> # 単に私の勉強不足なのかもしれません。C言語の基礎知識でしょうか?
> # 戻り値として定義してある関数を呼ぶだけでも、戻り値分のサイズがスタックに確保
されるの
> でしょうか??

C言語と言うよりもC++言語と言った方が良いと思います。
C言語では配列をそのまま返すような事はできませんから。
C言語だとこういうケースではアドレスで返すはずです。
中身的にはBanさんか説明されている通りだと思います。
あと、今されているように値返しする場合は、一時オブジェクトが
作成されるのでスピードも遅くなります。
CEの場合、環境的にPCよりもプアなので速度的には不利だと思います。
値返しの方がクラス内のデータ保護には良いのですけれど、
オブジェクトの生成は結構コスト高なのでループ内で連続して呼ばれる
ような場合は結構足を引っぱりますし。
あと、CEで10KBもあるような変数はスタックに積むべきではないと思います。
関数は基本的に何処からでも呼ばれる可能性がありますから
呼ばれたときにスタックに十分な空きがある保障はありません。
個人差はあると思いますが、私の場合だと1KB以上はヒープを使います。
ローカル変数に確保するのは大きくても数百バイトくらいまでです。
CEだと数百バイトでもどうしようかと思ったりします。

ミミ 2006/01/22(日) 11:12:05
[[解決]]
ミミです。

皆様のアドバイスにより、おかげさまで解決することができました。


>【ミミ 2006/01/17(火) 00:51:34】
>戻り値として定義しているだけの、★2、★3でもスタック消費されている

BAN様 と PATIO様 のご説明にありました「無名の一時変数」について調査を行いました。
MY_TABLE を戻り値とする関数を経由する回数を変えて試行してみたところ、
意図する結果となりました。やはり一時変数により、スタックを消費していたという
結果になります。
 ・OnButton2() -> Func1() -> Func2() の順で呼ぶ → 残りのスタックは n バイト程度
 ・OnButton2() -> Func1()       の順で呼ぶ → 残りのスタックは n + MY_TABLE 
バイト程度

>★1ではローカル変数(スタック)ではなく、メンバ変数(ヒープ)として確保し、
>Func1()、Func2()も MY_TABLE 型のポインタでやりとりしようと考えています。

この方法で開発中のプログラムにも修正した所、スタック消費量が
3KB 程度の消費量まで回復しました。(【ミミ 2006/01/17(火) 00:51:34】の結果と同じ)

構造体が戻り値として定義できるのは、C++ ならではなのですね。
正直見落としていましたので、とても勉強になりました。


>【PATIO様 2006/01/17(火) 13:47:41】
>個人差はあると思いますが、私の場合だと1KB以上はヒープを使います。
>ローカル変数に確保するのは大きくても数百バイトくらいまでです。
>CEだと数百バイトでもどうしようかと思ったりします。

CE の世界での開発者の考え方も得られたので、とても嬉しく思います。
最近は『メンバ変数をたくさん使用すると、それぞれの関数の独立性が薄くなる』
という考え方を元に、極力メンバ変数は使用せず、引数を利用していました。

しかし、例えば func1()に TCHAR szPath1[MAX_PATH] と定義しただけでも
520 KB のサイズがスタックに確保されてしまいますので、『極力メンバ変数を
使用しない』という自分の今までの考え方を改善し、臨機応変に対応する方が
いい気がしてきています。

何にせよ、今回のバグ探しにより得られた事は大変多く、技力向上にも
なったと思います。

皆様、ありがとうございました。

Ban 2006/01/22(日) 14:12:27
> 構造体が戻り値として定義できるのは、C++ ならではなのですね。
> 正直見落としていましたので、とても勉強になりました。

いえ、構造体は C でもできるはずですが。
そして、配列は C++ でもできないはずですが。

ミミさんの例では
> MY_TABLE 型のポインタ
と書いてあり、勝手に私は構造体だと認識していましたが、
PATIOさんのご回答は、
> C言語では配列をそのまま返すような事はできませんから。
配列と書かれていますので、何か誤解があるのかもしれません。

Ban 2006/01/22(日) 14:41:54
もしかすると、K&R 時代の C (ANSI規格化以前)だと構造体は戻り値にできないかも。
# 構造体の = によるコピーができかった時代

Ban 2006/01/22(日) 14:44:36
検索したら、C FAQにありました。
http://www.kouno.jp/home/c_faq/c2.html
<引用>
構造体を、変数に代入することも、関数に引数として渡すことも、
関 数の戻り値としても使うこともできると聞いた。
けれどK&R初版には できないと書いてある。
</引用>
きょうびのコンパイラ(たいていC89準拠?)であれば、まず大丈夫かと。

PATIO 2006/01/23(月) 10:21:26
> PATIOさんのご回答は、
>> C言語では配列をそのまま返すような事はできませんから。
> 配列と書かれていますので、何か誤解があるのかもしれません。
すいません。誤解してました。
ソースを見直すと確かに構造体になってますね。
只、私の認識では構造体も値返し出来ないという認識だったので
誤解していなくても同じレスがついていたと思います。

最新のC言語では構造体も値返しできるのですか。
私のC言語の知識も錆付いてきていますね。
私の中ではC言語で値返しできるのは組込み型のみという認識のままです。
となると、.NET2003あたりのコンパイラなら大丈夫なのかな。
一度、調べてみよう。
VC6で出来たかどうかも確認しときたいですね。
ちなみに私の周りにいる人間は多分、C言語で構造体の値返しが出来るというのは
知らないと思います。

Ban 2006/01/23(月) 10:44:37
VC7.1は実際に試して可能で
した。
特に意識せず使ってましたが
、
怒られた記憶もないので、
VC6やGCC、BCC等でも通る
と思います。
#逆に怒られるコンパイラを
知らないかも

Ban 2006/01/23(月) 10:51:40
VC6でも普通に通ります。

Ban 2006/01/23(月) 10:57:54
↑実際にやってみました。

> 最新のC言語では構造体も値返しできるのですか。
最新(C99)でなく、C89とかでも通るはずです。

ITO 2006/01/23(月) 20:44:09
>2006/01/10(火) 10:25:31 
のPATIOさんご意見で、「ヒープ領域から取得する」というお話がありました。

僕が参考に示した、
Windows CE .NET の高度なメモリ管理
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/jpdnce/htm/advmemmgmt.asp
に、Windows CEでのヒープメモリーの使い方が書かれています。
規模の大きな構造体は、ヒープからとることが出来ないのでしょうか。

構造体を、ポインターにして引数として渡してあげれば、その関数の中で値を書換え可能
だと思いますが、どうでしょうか。
わざわざ戻り値をしなくてもいいような気がします。

ミミ 2006/01/24(火) 00:47:47
Ban様、PATIO様、ITO様、ご返信ありがとうございます。

特に、実際に戻り値が構造体の時の動作検証まで行っていただいた Ban様には
何とお礼を申し上げたらよいか・・。本当にありがとうございます。

自分も(戻り値が構造体)VC6で試してみましたが、
特に警告も表示されずに実行できました。
# PCのスタック域(1MB)は CE(58KB)と比較すると大きいとはいえ、
# 構造体分の大きさを消費していることには変わりありませんが・・。


一方で、ITO様のご指摘、仰るとおりです。

>【ミミ 2006/01/17(火) 00:51:34】
>この回避方法として、★1ではローカル変数(スタック)ではなく、メンバ変数(ヒープ)
>として確保し、Func1()、Func2()も MY_TABLE 型のポインタでやりとりしようと考えていま
す。

現在は、構造体を戻り値とする仕様をやめ、ヒープに予め確保した領域に対して
参照渡しでやりとりをするように修正いたしました。
これにより「無名の一時変数」によって無駄に消費していたスタック領域も、
抑える事ができました。
今後は、CEならではのスタックの制限について常に考え、開発を進めていこうと思っています。

>【ITO様 2006/01/14(土) 19:52:20】
ITO様の提示してくださいました2つのリンクのうちの「Windows CE .NET の高度なメモリ管
理」
ですが、今後時間をかけてじっくり読んでいこうと考えています。
今後も CEの開発(もとい、通常のPCにおいても)を行って行く限り、
絶対に必要な知識だと思っていますので・・。

古いスレッドには追加発言できません。