モジュール型変数の実体サイズを取得したい
ht. 2013/7/10(Wed) 04:49:34|NO.55593
現在、異なる型を混合して扱うことのできるスタックのモジュールを作っています。
内部的にはWindowsAPIのHeapAlloc関数やdupptr命令等を駆使して、
それぞれの型,値,サイズなどの情報を自前のヒープ領域に保持しています。
そのサイズ情報について、文字列型はstrlen,実数型は8byte,後は一様に4byteとして
算出可能と思っていたのですが、どうやらモジュール型変数のサイズは固定ではなく
プロパティ(モジュール変数)を内包していてモジュール毎に可変らしいことが分かりました。
私の環境ではモジュール変数が一つ増える毎に実体のサイズが48byte程度増えます。
(以下の検証コードより推測)
前置きが長くなりましたが、モジュール型変数の実体サイズを得る方法はあるのでしょうか。
onerrorをキャッチすれば強引に取得できないこともないですがあまりやりたくありません。
::検証コード
/*
- 同じモジュール型変数を二つ用意してaからbにコピーする
- その推移を幾つかのモジュール変数をダンプしてチェックする
- ループ中にエラーが出たらそこが実体サイズと判断する
*/
#module Mod m_str1, m_str2;, m_str3 // アンコメントで約48byteコピー量が増える
#modinit str _s1, str _s2
m_str1 = _s1
m_str2 = _s2
return
#modfunc output
mes strf("str1: %s, str2: %s", m_str1, m_str2)
return
#global
newmod a, Mod, "complete1", "complete2"
newmod b, Mod, "yet", "yet"
repeat
offset = 4 * cnt
title strf("%d~%d byte", str(offset - 4), str(offset))
lpoke b, offset, lpeek(a, offset)
output b
wait 10
loop
レノス 2013/7/12(Fri) 21:46:34|NO.55640
おせっかいだと思いますが、モジュール型変数が所有するモジュール変数たちの生存期間は
その元々のモジュール型変数が書き換わるか消滅するまでなので、
モジュール型変数のデータをちゃんとコピーするには、いわゆるディープコピーを行う必要があります。
(move なら楽そう)
また、HSP本体のソースコードは OpenHSP で公開されています。ご参考に。
// #module 略
newmod a, Mod, "complete1", "complete2"
dupptr a_fv, varptr(a), 16 // a の値 : FlexValue 構造体
mes a_fv(2) // → 96 (byte)
>蛇足
ちなみに、モジュール型変数に対応できないですが、次のようにスタックを作ることもできます
#module Value v
#modfunc value_get var r
r = v
return
#modfunc value_set var r
v = r
return
#global
#module Stack arr_, cnt_
#modfunc stk_push var r
newmod arr_, Value
value_set arr_(cnt_), r
cnt_ ++
return
#modfunc stk_pop var r
if ( cnt_ == 0 ) : // 失敗
cnt_ --
value_get arr_(cnt_), r
delmod arr_(cnt_)
return
#global
newmod stk, Stack
t = "pi" : stk_push stk, t
t = 3.14 : stk_push stk, t
stk_pop stk, t : mes t
stk_pop stk, t : mes t
ht. 2013/7/14(Sun) 08:43:46|NO.55667
>レノスさん
しばらく開発Wikiを読んで変数はPVal構造体で管理されていると思い込み、
ずっとそちらのソースを探って悪戦苦闘していました。FlexValue構造体というものが別にあったんですね。
>おせっかいだと思いますが、モジュール型変数が所有するモジュール変数たちの生存期間は
>その元々のモジュール型変数が書き換わるか消滅するまでなので、
>モジュール型変数のデータをちゃんとコピーするには、いわゆるディープコピーを行う必要があります。
モジュール型変数のmemcpyでディープコピーをした気になっていました。
スタックについてはモジュール型変数対応で、元の変数に依存しない仕様を意図していたのでご助言感謝致します。
どうやらFlexValue構造体の二番目の要素にはモジュール変数の実体?のアドレスがあるらしいので、
それをコピーすることで目的の動作を得ることができました。
遅くなりましたがこれで何とか解決です。ご回答ありがとうございました。
需要に欠けると思いますが、モジュール型変数を実体コピーするソースコードを公開しておきます。
/*
モジュール型変数aを新しくbに複製する
*/
#uselib "kernel32"
#func RtlMoveMemory "RtlMoveMemory" int, int, int
#module Mod m_str1, m_str2
#modinit str _s1, str _s2
m_str1 = _s1
m_str2 = _s2
return
#modfunc output
mes strf("str1: %s, str2: %s", m_str1, m_str2)
return
#global
newmod a, Mod, "complete1", "complete2"
dupptr a_fv, varptr(a), 16 // a の値 : FlexValue 構造体
// シャローコピー
sdim b, a_fv(2)
dupptr b, varptr(b), a_fv(2), 5
RtlMoveMemory varptr(b), varptr(a), a_fv(2)
// ディープコピー
dupptr b_fv, varptr(b), 16
RtlMoveMemory b_fv(1), a_fv(1), a_fv(2)
// aを削除しbが生き残っていることを確認
delmod a
output b