HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2009
0808
SATTO#modtermをつかうとランタイムエラー6解決


SATTO

リンク

2009/8/8(Sat) 02:19:11|NO.26888

環境
OS:WindowsXPSP3
HSP:バージョン3.1


#module mod a #modinit return #modterm array p1 return #global newmod modvar, mod newmod modvar, mod delmod modvar(1),a
上記のソースコードを「コンパイル+実行」させた後ウィンドウを閉じると
以下のようなエラーメッセージが表示されます
Runtime Error!
Program: D:\Program files\hsp31\hsp3.exe
This application has requested the Runtime to terminate it in an usual way.
Please contact the application's support tearm for more information.

ちなみに、modvarを全部delmodした場合は表示されませんでした
これは仕様と割り切るしかないのでしょうか



この記事に返信する


shinkun

リンク

2009/8/9(Sun) 09:42:51|NO.26933

リファレンスに #modterm に関する詳しい解説が無く、また、HSP 内部の実装コードも見たことが無いので推論の域を出ませんが、結論から申し上げると、今回の件は、SATTO さんが考えているように HSP の仕様だと割り切るしかないでしょう。#modterm にパラメータを設定した場合は、暗示的なモジュールの破棄が出来ないのです。

暗示的というのは、スクリプト上で delmod を書いていないのに delmod と同じ処理が実行される、という意味です。スクリプト上に明示されていないから暗示という訳です。

私がテスト&考察した結果、どうやら HSP はモジュール変数を暗示的に破棄する場合、そのモジュール変数を delmod するコードを、適切な位置に挿入したのと同じ効果の処理を自動的に行うようです。さらに、パラメータ付きの場合はそのパラメータを 0 として呼び出すようです。

ですから、SATTO さんのスクリプトにおいては、次のコードが生成されたのと同じになります。

#module mod a #modinit return #modterm array p1 return #global onexit goto *exit ; このコードが HSP によって自動挿入される newmod modvar, mod newmod modvar, mod delmod modvar(1), a stop *exit ; このコードが HSP によって自動挿入される foreach modvar delmod modvar(cnt), 0 ; パラメータには 0 が記述される!! loop end
自動的に破棄コードを生成してくれるのは良いものの、生成された delmod のパラメータが 0 なので、受け取り側の p1 としては不適です。配列を渡すべき所に 0 という整数を渡しているからです。そのため、ランタイムエラーとして怒られたのではないかと思います。
ただしこの場合、int のパラメータならば何事も無く実行される事になりますし、実際にそうでした。ですが、パラメータはすべて 0 で固定されていますので、果たしてそれが役に立つかどうかは疑問です。

上記コードを実行すると、ウィンドウを閉じる時に「変数名が指定されていません」というエラーが発生します。
これは SATTO さんのスクリプトで出るダイアログとは異なりますが、破棄するコードがスクリプトに明示されているか否かの違いによって、エラーの原因を HSP が突き止められたかどうかの差として表れたものだと思います。

解決策というか回避策としては

1.パラメータ付き #modterm を利用する場合は、そのモジュールを格納する全ての変数に対して利用を終えた後で地道に delmod をしてまわる
2.パラメータ付き #modterm を使わないようにする

これらのどちらかです。
個人的には、パラメータ付き #modterm を使わない方が良いかと思います。パラメータを付けた所で利点よりも欠点の方が多いと思いますので。

こういう機能が存在すること自体は決して悪い事ではないと思うのですが、せめて「詳しい解説はないけれど、一応こんな事が出来るよ」というようなユーザーを変に惑わす中途半端な説明は止めて欲しいところですね。



SATTO

リンク

2009/8/9(Sun) 09:50:33|NO.26934

shinkunさん
やはりそういう風に考えますよねえ
一応、回避策として、プログラム終了時のモジュール変数の破棄処理を自前で用意してみましたが
おっしゃるとおりパラメータ付き#modtermで定義せず#modfuncとして破棄処理を記述したほうが
よさそうですね



shinkun

リンク

2009/8/9(Sun) 10:50:08|NO.26937

SATTO さん

#modfunc でモジュール変数の破棄、ですか…。
ちょっと腑に落ちません。それだと変数は破棄出来ませんけど…。

もしかしてそれは、モジュール変数の破棄ではなくて、別の何かの破棄じゃないでしょうか?
例えば………
うーん、何か例を挙げようと思ったのですが、良い例が思い浮かびません。スイマセン。

もし宜しければ、どんな事をやろうとなさっているのか教えていただけませんでしょうか?
パラメータによって破棄の仕方に差異が出てくる例というものに興味があります。



SATTO

リンク

2009/8/9(Sun) 12:04:47|NO.26943

作ろうとしていたのはこんの感じのものですね
RPGのマップ上のキャラクタを管理するサンプルです

#module #define prmstack 207 #define global ctype pvalptr(%1) pvalptr_(%1, 0) ; 指定した変数のPVALポインタ値を取得 #define global ctype getaptr(%1) pvalptr_(%1, 1) ; 指定した(配列)変数のAPTR値を取得 #defcfunc pvalptr_ var _p1, int _p2 mref HSPCTX, 68 dupptr vptr, HSPCTX.prmstack, 8, 4 return vptr(_p2) #global #module chara x, y #modinit int _x, int _y, array _map x = _x : y = _y _map(x,y) = getaptr(thismod) ;作成した要素番号を書き込む return ;キャラを削除、マップからも要素番号を消去 #modfunc del array _map _map(x,y) = 0 delmod thismod return #global #module #deffunc mes_array array _map for ycnt, 0, length2(_map) string = "" for xcnt, 0, length(_map) string += ""+_map(xcnt, ycnt)+"," next mes string next return #global dim map, 5, 5 newmod enemy, chara, ,, map ;enemy(0)は使用しない newmod enemy, chara, 3, 2, map newmod enemy, chara, 1, 1, map pos 0, 0 mes "mapの中身" mes_array map mes "enemyのリスト" foreach enemy mes "enemy("+cnt+")" loop mes "要素1番と2番を削除" del enemy(1), map del enemy(2), map mes "mapの中身" mes_array map mes "enemyのリスト" foreach enemy mes "enemy("+cnt+")" loop



shinkun

リンク

2009/8/9(Sun) 13:31:58|NO.26950

あー、成程…。

マップとキャラクタ情報の関連付けを解除するのにパラメータが必要な訳ですね。
確かにキャラクタが死ぬ時に勝手にマップからキャラクタ情報が消えてくれるとありがたい…。

HSP でも配列に対して正しくポインタの逆参照なんかが出来るならば、
事前に map のポインタ取得しておくことで chara の del 呼び出し時に map 指定しなくても良くなるんですけどね…。
それなら、パラメータなしの #modterm で良いのですが…。

しかし、この手のプログラムの場合、キャラクタの多くは明示的に破棄することになるでしょうから、
#modfunc で必要十分ですね。
あんまりポインタバリバリに使っちゃうと、C と何が違うのだって話になっちゃいますし。(^^;

わざわざありがとうございました!!
おかげでスッキリしました!!



shinkun

リンク

2009/8/11(Tue) 23:43:47|NO.27011

今っさら〜な感じですが、SATTO さんのスクリプトを、
パラメータなし #modterm で実装してみました。
これなら暗示的な破棄も可能です!!

基本的な考えは、全 chara モジュールが共有する map のアドレスを
あらかじめ charaInit で取得しておく事で、chara 破棄時に map 情報を
パラメータとして受け取らなくて済むようにしようというものに基づいています。

あと、PVAL 構造体などの HSP システム自体の仕組みを知らないと
コード化できない部分が気持ち悪かったので、
標準で用意されている varptr, dupptr で代用してみました。
これでも十分気持ち悪いけれど…。


#const VAR_TYPE_INT 4 #const VAR_TYPE_MODULE 5 #module chara x_, y_ #defcfunc _charaGetMapAddress int x, int y return map_ + 4 * (x + length_ * y) #deffunc _charaWriteMyAddressToMap int x, int y, int addr, local p dupptr p, _charaGetMapAddress(x,y), 4, VAR_TYPE_INT@ p = addr return #deffunc charaInit array map map_ = varptr(map) length_ = length(map) ; dupptr では配列を復元出来ないので、 ; アドレス算出可能な様に配列サイズを記録しておく return #modinit int x, int y x_ = x y_ = y _charaWriteMyAddressToMap x, y, varptr(thismod) return #modterm _charaWriteMyAddressToMap x_, y_, 0 return #modfunc charaTest mes "座標 (" + x_ + "," + y_ + ") のキャラクタ" return #global #module aux #deffunc auxShowMap array map, int pos_x, int pos_y, str text pos pos_x, pos_y mes text y = 0: gy = pos_y + ginfo_mesy repeat length2(map) x = 0: gx = pos_x repeat length(map) pos gx, gy mes strf("%8x",map(x,y)) x++ gx += ginfo_mesx + 10 loop y++ gy += ginfo_mesy loop return #deffunc auxGetChara var p, int addr dupptr p, addr, 16, VAR_TYPE_MODULE@ return #global ; ---- ; ここからテスト... ; ---- font msgothic, 12, 16 ; マップ生成 dim map, 5, 5 auxShowMap map, 0, 0, "初期状態" ; キャラクタ生成 charaInit map ; マップと全キャラクタを関連付け dimtype x, VAR_TYPE_MODULE, 3 ; あらかじめ最大使用数分のメモリ領域を確保して置かないと、 newmod x, chara, 2, 1 ; 配列の伸張によるメモリ再確保が起きて map に書き込んだ newmod x, chara, 4, 4 ; アドレスが無効になってしまう!! newmod x, chara, 1, 3 ; その点で言えば、アドレスより index を記録した方が無難だが…。 auxShowMap map, 0, 100, "キャラクタ生成" ; キャラクタのアドレス情報を表示 pos 400, 0 mes "キャラクタ・アドレス" foreach x mes "x(" + cnt + ") = " + strf("%8x",varptr(x(cnt))) loop ; マップに格納されたキャラクタアドレスからキャラクタを復元できるかテスト auxGetChara p, map(4,4) ; アドレスからキャラクタを復元 charaTest p ; 動作テスト ; キャラクタ破棄 delmod x(0) delmod x(1) ;delmod x(2) auxShowMap map, 0, 200, "キャラクタ破棄" ; ここでは、x(2) を明示的に破棄していない。 ; HSP アプリケーション終了時に起きる暗示的な破棄によって破棄させてみる。 ; 終了時にエラーが出ないなら、暗示的な破棄も正常に終了した事に。 stop

今回の事を通してみて、HSP でポインタ使ったり、モジュール同士を関連付けたり
っていうのは労力の割りにリターンが少ないなと改めて痛感しました。
私は素直に配列、モジュール(単体)、gosub でやってこうと思います。



ONION software Copyright 1997-2023(c) All rights reserved.