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


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0408
kanamaruhspで使えるdllの作り方39解決


kanamaru

リンク

2020/4/8(Wed) 16:15:39|NO.90002

前のスレッドで説明した通り、dllを作っています。
で、試作品は既に完成して、実際にプログラムを作ってみました。
しかし、返り値が想定と異なっていました。
(返り値はstrになってほしいのにintになっている)
そこで聞きたいのですが、
hspで使えるdllを作るとき、
文字列を引数にとり、文字列を返す関数はどうやって作ればいいのでしょうか。
このdllは一応他の言語でも使えるようにしたいので、hspsdkは使っていません。
それともhspsdkを使った方がいいのでしょうか?



この記事に返信する


kanamaru

リンク

2020/4/8(Wed) 16:17:22|NO.90003

補足として、いかに今作っているdllの関数定義を書いておきます。
const char* reg_match(char* target, char* pattern);
const char* reg_submatch(char* target, char* pattern);
void reg_matches(const char* retvar[], char* target, char* pattern);
const char* reg_replace(char* target, char* pattern, char* repstr);



vof

リンク

2020/4/8(Wed) 17:59:10|NO.90004

戻り値が文字列となるDLL関数はhspsdkを使ったHSP専用のDLLでないとできないです。
kanamaruさんの作った関数では文字列へのポインタが返ってます。
普通のDLLでは#defcfuncの中でDLL関数から受け取った文字列を返すようにすれば
間接的にですが希望の処理ができます。



kanamaru

リンク

2020/4/8(Wed) 18:49:12|NO.90006

ありがとうございます。
hspsdkを使いプラグインを作り始めました。
reg_match、reg_submatch、reg_replaceはどうにかしました。
(exinfo->refstrに返り値を入れればいいんですよね?)
残り、reg_matchesを実装しようと思ったところで、
引数に配列がある場合、どうすればいいのかわかりませんでした。
code_getpvalを使えばいいのだと思いますが、
サンプルでは使ってませんでした。
code_getvaを使えばいいのでしょうか?



kanamaru

リンク

2020/4/8(Wed) 19:02:38|NO.90007

今サンプルをもう一度みてみたら、
関数の返り値の処理が間違っていたようです。
修正しました。
ちなみに、蛇足ですが、
hspのプラグインとしても通常のdllとしても使えるようにして見ました。
hspのプラグインとして作っちゃうと他の言語で使えないと聞いたので、
ちょっとした実験です。
といっても大した仕組みではありませんですが。



X

リンク

2020/4/8(Wed) 20:06:44|NO.90008




kanamaru

リンク

2020/4/8(Wed) 22:03:21|NO.90010

ありがとうございます。
参考になりました。
エラーを修正していたところ、
エラー C4703 初期化されていない可能性のあるローカル ポインター変数 'opal' が使用されています hspregexp hsp3plugin.cpp 63
というエラーが発生していたのですが、
このエラーはどうやって修正すればいいでしょうか?
bms_sendという関数は使ってないように見えますし、
定義を丸ごと消してもいいのでしょうか?
個人情報みたいなのが含まれていたので、影響ない程度に削らせていただきました。



kanamaru

リンク

2020/4/8(Wed) 22:35:25|NO.90011

該当する変数を初期化することでエラーを消しました。
で、完成したdllを使って、プログラムを使ったところ、
プログラムが強制終了してしまいました。
dllと検証に使ったプログラムと
プロジェクトを圧縮しました。
https://www.dropbox.com/s/xv93pma22r634kr/hspregexp.zip?dl=0
原因わかる方はいますか?
心当たりは普通のdllとしても使えるようにしたことぐらいだけど、
影響あるのかな?言い換えると関数が増えただけだし。



MillkeyStars

リンク

2020/4/8(Wed) 23:39:17|NO.90014

単純に ref_sval のメモリが確保されていないので、null ポインタエラーで落ちてるだけ。



X

リンク

2020/4/8(Wed) 23:46:18|NO.90015

上記えくー様のHPにあるように文字列は少し癖があります。

#defcfunc HOGEHOGE str _p1, str _p2, str _p3 p1 = _p1 p2 = _p2 p3 = _p3 reg_submatch(p1, p2, p3) return
とする為に<string>をインクルードしstdstringをお使いください。
HSPのように文字列の代入や連結がしやすくなるため取っ付き易くなります。
取り合えず該当箇所のみ…

char* p1; char* p2; char* p3;


std::string p1; std::string p2; std::string p3;

reg_replaceを抜粋
他は適宜修正されてください。

case 0x03: // reg_replace p1 = code_gets(); p2 = code_gets(); p3 = code_gets(); ref_sval = (char*)reg_replace((char*)p1.data(), (char*)p2.data(), (char*)p3.data()); break;
戻り値の個所を

return (void *)&ref_sval;
から

return reinterpret_cast<void*>(ref_sval);
と変更されてください。



kanamaru

リンク

2020/4/9(Thu) 08:00:43|NO.90017

ありがとうございます。
Xさんの言う通り、std::stringを使うように書き換えてみました。
MillkeyStarsさんの言う通り、メモリ確保しようとしたのですが、
長さ不明の文字列のためのメモリ確保の方法がわからなかったので、
ref_svalをstd::string型にして、
data()関数でchar*にするというXさんの方法を使いました。
しかし、mesboxに表示された文字列は想定と違いました。
ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン
ってなったのですが、原因わかりますか?
dropboxの方は更新しました。



f(昼休み)

リンク

2020/4/9(Thu) 12:18:18|NO.90018

まず、HSPに文字列を渡す為だけの関数作って、それでテストすれば良いんじゃね?
文字列はちゃんと渡せるのに実働で変になるならバグやろ。
問題点を切り分けろ。

参考
C側
int get(char* buf)
{
std::string result = "test";
if(buf != nullptr) strcpy_s(buf, result.size() + 1, result.c_str());
return result.size() + 1; // 文字列終端nullの分を+1
}

HSP側

#func get "get" var
#cfunc getSize "get" nullptr

sdim result, getSize()
get result
mes result


試してないから動くか知らんが。



X

リンク

2020/4/9(Thu) 12:25:09|NO.90019

確かにダウンロードしたものだとおかしな結果になりますね…
自分の環境がVS2015のためプラットフォームのバージョンを落とす必要はありましたが
kanamaru様のコードは何も改変せず試したところ想定されている結果にはなったのですが。
debugだとおかしくなるのかな?これ以上は自分にはわからないです、すみません…

直接の解決にはなりませんがstd::regexは割と重い処理だったりします。
bregonig.dllでラッパーモジュールを最適化したほうが1.5倍〜2倍ほど高速になるのでそちらの方が良いような気もします。



kanamaru

リンク

2020/4/9(Thu) 12:42:13|NO.90020

Xさんの環境でビルドしたらきちんと動きましたか。
なんでだろう?
bregonigの方が高速なのですか…。
まあここまでやったんだし完成はさせておきます。
とりあえずXさんの環境でビルドして生成したdllを頂くことはできませんか?
実際に動くところを自分でも確認してみたいです
visualstudioの設定を見直してみます。
f(昼休み)さん、Xさんの話だとソースに問題はないようです。
なので今度別のプログラムを作成するときにでも参考にします。



X

リンク

2020/4/9(Thu) 13:08:14|NO.90021

こちらからどうぞ
https://www.amazon.co.jp/clouddrive/share/TAdavj8iyuedcS13c8vlwzNsc3F9ZwXCT1FDWfJl4hr
kanamaru様がビルドされた方には(原本)と付けわけております。
HSP3.51 3.4で確認したものです。



X

リンク

2020/4/9(Thu) 13:10:43|NO.90022

連投すみません。
reg_replaceしか確認しておりません。
他の関数については未確認です。



kanamaru

リンク

2020/4/9(Thu) 13:22:00|NO.90024

こちらで確認をしてみたところ、
reg_replaceしか動いてないようです。
ソースを見直して、修正してみます。
後、std::regexは遅いとのことで代わりになりそうなのを探してみました。
http://www.akenotsuki.com/misc/srell/
とかだと速度はどうなのでしょう。
速度を計測するのは苦手なので、計測してくれる人はいないでしょうか。
とりあえず、std::regex版を完成させないことには進まないので
原因を探してみます。
ソースはdropboxで公開してるので原因に心当たりがある人は
教えてくれるとありがたいです。



MillkeyStars

リンク

2020/4/9(Thu) 13:37:47|NO.90025

【main2.cpp 抜粋】

const char* reg_replace(char* target, char* pattern, char* repstr) { std::string s = std::regex_replace(target,std::regex(pattern),repstr); return s.c_str(); //←これ関数を抜けたら破棄されてるよね・・・ }
HSP みたいに、関数を抜けても維持してくれないから気を付けてね。



kanamaru

リンク

2020/4/9(Thu) 14:33:40|NO.90026

MillkeyStarsさんのを聞いてプログラムを修正したところ、
こっちでビルドしたものも動くようになりました。
Xさんの環境だと破棄されないようになっているのでしょうか?
しかし、reg_matchesだけは、動きませんでした。
見慣れないエラーで、
vector subscript out of range
というものです。
vectorに関係するところを確認しているのですが、
原因がわかりません。
dropboxは更新しました。



X

リンク

2020/4/9(Thu) 15:16:00|NO.90027

これまでにいくつか出ている物から

code = {" mes "1" mes "2" ; t mes "3" ; t mes "4" // t mes "5" // t "} code = replace(code,";.*", "\n") // セミコロン code = replace(code,"//.*", "\n") // スラッシュx2
これをベースに100000回ループで
mod_regexp.as使用

code = replace(code,";.*", "\n") // セミコロン code = replace(code,"//.*", "\n") // スラッシュx2
このパターンで3200msから3300msほど


code = replace(code,"(;|//)[^\\r\\n]*$", "") // セミコロンとWスラッシュ
このパターンで2650msから2680msほど

BREGEXP.hsp + bregonig.dll使用

BSubst code, "s#(;|//).*# #[m][g][R]"
このパターンで750msから780msほど

VBScript RegExpをプラグイン化した物 replace準拠
このパターンで2150msから2200msほど

kanamaru様のstd::regex使用reg_replace2回で置換
1550msから1620msほど

BREGEXPのソースが転がっているのでプラグイン化
つーさ様のモジュールに準拠BSubst使用で420msから450msほど

正規表現を一切使わずにgetstr instr split pokeで愚直に行って650msから680msほど
CPUはRyzen5 2400Gで計ったものです。

区切り文字の種類が両手で数えるほどなら正規表現より便利かとは思います。

BREGEXPを取り込んでしまうのが速く見えますがUTFは一切使えません。
HSPもマルチプラットフォームを視野に入れてるように感じますので今後難はあるかと思います。
あくまで正規表現でやり通す必要があるなら鬼車が開発を再開しているようですしR〇byの前例を考慮した上で
おにたま様に正式に連絡を取り合っていただき正式に取り込んでいただくのが使う側としてはありがたいかもしれませんね。
そこまでしないといけないのかは自分にはわからないところですが…



kanamaru

リンク

2020/4/9(Thu) 15:29:17|NO.90028

Xさん、ありがとうございます。
std::regexは遅いって話だけど、一応hsp標準のものよりは早いみたいですね。
先述のエラーですが、
&v[0]をv.data()にすることで発生しなくなりました。
が、変数への代入ができてないようです。
main2.cppが原因なのか
main.cppが原因なのか。
Xさんが教えてくれたURLをもう一度読み直してみます。



kanamaru

リンク

2020/4/9(Thu) 17:30:32|NO.90030

プログラムを見直したり、
Xさんが教えてくれたURLを見たりしましたが、
やっぱり配列に代入する方法がわかりません。
Xさんが教えてくれたURLの
http://fe0km.blog.fc2.com/blog-entry-118.html
を参考にしてプログラムを書き換えたのですが、
そもそも引数に指定した変数の型がintのままです。
長さも1のままだし。
配列に代入するところを抜粋します。

pval = code_getpval(); HspVarCoreReset(pval); len=reg_matches(_p.data(), code_gets(), code_gets()); stat = len; for (int i = 0; i < len; i++) { exinfo->HspFunc_array(pval, i); code_setva(pval, pval->offset, HSPVAR_FLAG_STR, _p[i]); } break;
_pはvector<char*>となっています。
原因わかりますか?



kanamaru

リンク

2020/4/9(Thu) 17:46:49|NO.90031

書き忘れましたが、reg_matchesの返り値はintに変更しました。
マッチした数が入ってます。
返り値を変更したのは、マッチした数をstatに代入したかったからです。
また、配列に代入する長さを知るためでもあります。
後、reg_matchesがそもそも動作しない可能性があるので、
reg_matchesを見てくれるとありがたいです。
dropboxは更新しました。



kanamaru

リンク

2020/4/9(Thu) 17:49:20|NO.90032

何度もすいません。
返り値を変えたのは、main2.cppの方のreg_matchesです。
誤解が無いように書いておきます。



X

リンク

2020/4/9(Thu) 18:55:51|NO.90033

じっくりダウンロードしてみることが出来ないので気になった部分だけ。
code_get○○といくつか種類があるわけですが、code_gets()は次の引数に手を付けた時点でおかしなことになるので
即座にstring型に代入し実体化させそこから別の関数へと渡すようにした方が良いです。
パフォーマンスは落ちますがcode_gets()は曲者だと刷り込んでください。
またプラグイン側での変数の受け取りは配列であろうとなかろうと

pval = code_getpval();
ではなく

PVal* pval; APTR aptr = code_getva(&pval);//変数の取得とインデックス(0であったとしても)の取得
とそういうものなんだと覚えてしまっていた方が後々楽です。

HSPへの戻り値に配列として渡す時は

HspVarCoreReset(pval); exinfo->HspFunc_array(pval, インデックス);
はセットになります。

for (int i = 0; i < len; i++) { HspVarCoreReset(pval);//配列初期化 exinfo->HspFunc_array(pval, aptr + i);//インデックス指定 code_setva(pval, aptr + i, HSPVAR_FLAG_STR, _p[i]);//代入 }
という流れになります。
インデックスでもオフセットでもわかりやすいように捉えてくださいませ。
あとHSPのお作法だけ覚える形になるのもあれなわけですがstatマクロはHSP_Statにでも変えておいた方が良いかと。
C自体にstat関数があるので衝突してエラーを出すことがあります。



kanamaru

リンク

2020/4/9(Thu) 19:47:33|NO.90034

Xさんの話を参考にして書き換えたところ、
またvector subscript out of range
のエラーが発生しました。
たぶんreg_matches(main2.cpp)を間違えていて、
きちんと第一引数に代入されてないのにlenを使って
ループを回していることが原因だと考えられます。
ということで、reg_matchesを書き換えようと思ったんですが、
第一引数の配列に対しmallocでメモリ確保して、
forでループ回して代入しても
エラー変わらないし、どうすればいいんでしょう。
そもそも間違っているか、
mallocの引数にvectorのsize()を指定したのがダメなのか。



kanamaru

リンク

2020/4/9(Thu) 21:19:32|NO.90036

調べてみたら、vectorって空の時data()が先頭アドレスになるか保証されてないようです。
なので、とりあえず""を一個入れておきました。
配列の一個目になるわけだから、上書きされるだろうし、
たぶん問題ないはず。
すると、エラーが変化しました。
配列の要素が無効です。
というhspのエラーが発生しました。
これってどういうことなんでしょう?
dropboxは更新しました。



kanamaru

リンク

2020/4/9(Thu) 21:54:38|NO.90037

とりあえず、mallocで確保するのはさすがにダメだろうということで、
とりあえず元のソースに戻しました。
それでも配列の要素が無効ですのまま変わらないので、
どうやら原因は空のvectorにdata()を使ったことだと考えていいとわかりました。
とりあえず発生するのがhspのエラーであることを考えたら、
原因は

HspVarCoreReset(pval);//配列初期化 exinfo->HspFunc_array(pval, aptr + i);//インデックス指定 code_setva(pval, aptr + i, HSPVAR_FLAG_STR, _p[i]);//代入
の中にあるとみていいと思うのですが、
教わった通りというか
教えてもらったのをそのままコピーしたので、
原因が全然わかりません。



kanamaru

リンク

2020/4/10(Fri) 10:40:22|NO.90041

ソース眺めて気が付いたんですけど、
これってreg_matches(main2.cpp)の方に原因があるかもしれません。
vectorのポインタ渡しているけど、
そこへの代入が行われてない。
そうするとvectorの中身は空文字列の要素一個になる。
だけどlenは少なくともきちんと帰ってきているから
配列に代入しようとしてるけど要素一個しかないからエラーが発生してるのか?
だからエラー発生時にデバッグウィンドウ見たら
第一引数に指定した変数に
空文字列一個入っているのかもしれません。
というわけで、聞きたいんですけど、
vectorの先頭ポインタを使ってvectorの機能を使わずに
中身を書き換える方法ってありますか?



ベイン

リンク

2020/4/10(Fri) 19:20:43|NO.90047

> main2.cpp:35
> retvar = (const char**)malloc(v.size())

これはローカル変数 retvar への代入であって、
main.cpp で渡している vector への操作にはなっていません。

(引数の「char* retvar[]」は「char** retvar」と同じ意味です。
HSP の array 引数とは異なります。)

> vectorの先頭ポインタを使ってvectorの機能を使わずに
> 中身を書き換える方法ってありますか?

通常、そういうことはしません。
vector を操作したいときはバッファへのポインタ (data()) ではなく
std::vector へのポインタ(または参照)を渡してください。
例:


void f(std::vector<int>* v) { v->push_back(1); } void g() { std::vector<int> p{}; f(&p); // p[0] == 1 }

また、C++ は関数からどんな型のオブジェクトでも返すことができます。
reg_matches の場合はこの方針のほうが自然な気がします。
例:


std::vector<int> f() { std::vector<int> xs{}; xs.push_back(1); xs.push_back(2); return xs; } void g() { std::vector<int> ys = f(); // ys[0] == 1 // ys[1] == 2 }



kanamaru

リンク

2020/4/11(Sat) 10:02:02|NO.90051

僕としたことがすっかり引数にstd;;vector使うことを考えもしなかったです。
それで改良を加えたのですが、やっぱり配列の要素は無効ですとエラーが出ます。
そこで、ためしにsdimで要素3の配列にしてから引数に指定したところ、
それでも配列の一個目しか入ってませんでした。
原因わかりますか?
ちなみに返り値をstd::vectorにしたら中身が一個も入らず
変数がint型のままだったので
とりあえず引数に入れる形に戻しました。
dropboxは更新しました。



ベイン

リンク

2020/4/11(Sat) 16:43:41|NO.90057

vector 周りは直ってそうで、よかったです。
次はどこまで正しく動いていて、どこからおかしくなっているかを確認しましょう。

私は HSPSDK や std::regex の詳細をよくみてないので、
実際に何が問題なのかは分かりませんが、
例えば次のような点を確認するのはどうでしょうか。

- 入力を正しく受け取れていない可能性
- プラグイン側で命令の引数として受け取った文字列 (p1, p2 の値) が
期待したとおりの値であるか確認
- 入力まで正しくて、計算(reg_matches)が誤っている可能性
- reg_matches を直接実行して、結果がどうなるか確認
- 計算まで正しくて、出力(配列変数に代入するところ)で失敗している可能性
- HspFunc_array や code_setva の使い方があっているか確認
- そもそもテストケースが間違っている可能性 (まれによくある)

また、Visual Studio のデバッグ機能を使うといいかもしれません。
Debug モードでビルドしたプラグインを HSP で #regcmd に指定している場合、
「プロセスにアタッチ」(Ctrl+Alt+P)で hsp3.exe にアタッチすると、
プラグインのコードをデバッグ実行できます。
(プラグインのコードにブレークポイントを指定する必要があります。
Visual Studio でブレークポイントを配置する方法は適当に調べてください。)



kanamaru

リンク

2020/4/11(Sat) 17:58:10|NO.90059

とりあえず、第一引数の変数に値は帰ってきてるのか、
引数をきちんと取得できてるのかを調べてみるために、
第二引数と第三引数に指定した文字列を第一引数の変数に代入するプログラムを書きました。
すると、なんと同じエラーが出ました。
その後いろいろ試したところ、一部の原因はわかりました。
解決策はわかりませんが。
わかった原因は二つあります。
一つは、第一引数に指定した変数のサイズです。
当然、必要なサイズはマッチした数になるわけですが、
どうも自動でサイズが大きくはならないようです。
なのでdllの方でサイズを変更する必要があります。
ちなみに
pval->len[1]にlenを代入してもダメでした。
じゃあ、あらかじめsdimで確保したらどうなるのか
と思ったんですが、
変数の要素が一個しか代入されていませんでした。
そこで次の原因です。
reg_matches(main2.cpp)のアルゴリズムです。
これは、マッチしたらポインタを移動させて繰り返すという仕組みなのですが、
移動先がマッチした文字列の最後尾なんです。
で、マッチするのは各行。
つまり最後尾の後ろには改行があるんです。
じゃあ繰り返しで次どこを探すのかといえば
正規表現の特性上、
一文字目に改行があるんだから空文字列になります。
本当は次の行に探査してほしいのに。
これはマッチするのが行全部じゃなくても同じと考えられます。
その場合、マッチした後ろ改行までが次の探し場所です。
で、その場合、マッチしないんです。
その場合、whileを抜けて、
処理が終わります。
なので一個目しか入らない。
以上がわかった原因です。
たぶん正しいと思います。
しかし一行でマッチが一つだったらどうなるのかというと、
同じエラーが発生しました。
上二つの原因は複数行、あるいは複数マッチが故なのに。
そのため、他の原因も関わっていると思います。
以上のわかった原因の解決策はわかりますか?
もちろん不明な原因がわかったら教えてください



ベイン

リンク

2020/4/11(Sat) 18:31:01|NO.90060

調査お疲れさまです。

> どうも自動でサイズが大きくはならないようです。

HSP の dim 系の命令 (ldim/sdim/ddim/dim/dimtype) に相当する操作は
HSPSDK では exinfo->HspFunc_dim を使うとできます。

また、既存の配列の要素数を長くするには HspFunc_redim を使います。

HSPSDK の資料が hspsdk/hspdll.txt にあるので参考にしてみてください。
ウェブでも読めます: https://www.onionsoft.net/hsp/v36/hspsdk/hspdll.txt

それから、いまさらですが、reg_matches も他の言語向けに DLL から公開する予定だったんですね。
std::vector を受け取る/返すようにしてしまうと他の言語からは使えないのでご注意を……
(他の言語で std::vector へのポインタを用意できないし、DLL で公開する関数から std::vector を返すことはできない)。



kanamaru

リンク

2020/4/11(Sat) 19:46:41|NO.90061

ベインさん、ありがとうございます。
HspFunc_redim
を使ったんですけど、サイズが変わりませんでした。
たぶん指定した変数が配列だったからだとは思います。
なので、HspFunc_dimを使うことで指定した変数が配列でも配列じゃなくても対応できると思ったんですが、
len0に何を指定するのかわかりません。
sdimの第二引数ということは最長の文字列の長さでも入れればいいんでしょうか?
256を試しに入れたんですけど長さが変わりませんでした。
また、dllとして公開する云々はいったん考えずにhspから使えることを考えるようにします。
そもそも引数にvector使う発想にならなかったのはそれでしょうし。
とはいってもオーバーロードしてdllとして公開するのはvectorじゃない方にしてはあるんですけど。
それは置いておいて大丈夫です。



kanamaru

リンク

2020/4/11(Sat) 19:59:13|NO.90062

テストケースが間違えてました。
で、正しいテストケースで試したところ、
vector subscript out of range
原因なんだろうと思ったら、
reg_matches(main2.cpp)で一個しか返ってきてないんだから、
長さ伸ばしたら確かに範囲外です。
lenは正しくなかったよなと思って、
想定してる答えがマッチ数3なので直接指定したから
思いっきり範囲外指定しているようです。
ということでreg_matchesが正しい動作するようにするには
どうすればいいでしょうか。
とりあえず伸ばす長さはlen(配列の長さにしたい数が入っている変数)
を指定しておきます。



ベイン

リンク

2020/4/11(Sat) 21:53:07|NO.90064

配列変数に結果を格納する部分は動いたようで、よかったです。

正規表現はよく分からないので他の方にお任せます。
念のため文脈を整理しておくと:

1スレッド目: "正規表現で特定文字以降の文字列を消去してみたけどうまくいかない - HSPTV!掲示板"
https://hsp.tv/play/pforum.php?mode=all&num=89916

2スレッド目: "hspからjavascriptの実行 - HSPTV!掲示板"
https://hsp.tv/play/pforum.php?mode=all&num=89973

3スレッド目: ここ



リンク

2020/4/11(Sat) 23:25:02|NO.90065

すでに内容には全くついていけてませんが、非常に面白いです。



3k

リンク

2020/4/25(Sat) 18:26:11|NO.90186

特にコメントするつもりはなかったんですが、
流れを追っていくと是非はともかくHSP本家に入れようって話だったんですね。
なるほど、興味湧きました。
であれば辛口ですが問題箇所の指摘とサンプル実装の一つを投げておきたいと思います。

――――――――――
●まず前提の話で、CはHSPと違ってメモリ管理が厳密です、基本は自分で全てのメモリを管理する必要があります。
C++になって抽象化が進みましたが、最終的にメモリ管理をするのは自分です、ここは変わりません。

char*も勿論自分で管理が必要ですが、STLのvectorなども(ある程度自動でやってくれるとは言え)
メモリ管理は必要ですし、vectorに関しては同じ機能を持った簡易なコンテナー型を
実装できる程度の理解がないと扱うのは厳しいです。
例えばvectorは確保するのはdequeなどと違い確保される領域は連続領域であることが仕様で決まっており、
これを利用して簡易な動的配列型としても使える特徴がある…、などが分かることです。

ここでC++とSTLの話をするのは本筋ではないのでここで切り上げますが、
Cと連携できるネイティブのAPI設計ではメモリ管理はどうやっても避けて通れないので、
malloc/freeを始め基礎的な理解な無いのであれば手をだすべきではありません。
とはいえ、メモリ管理はCの入門書でも扱う内容なので、入門書を読破できれば躓いても乗り越えられるとは思います。

何が言いたいかというと、現時点(2020/04/20でのDropBoxから落としたもの)でのコードではメモリ管理が破綻しています。
とりあえずはDLLとしてではなく、HSPのプラグインとして閉じた形としておいた方が変なバグがでないと思います。

malloc/freeはじめ、メモリ管理を一通りできるようになってから、DLLとしてどこにメモリを置いておくか、等を意識して
再設計・実装してもらえたらと思います。

――――――――――
●2点目、reg_matchesを正しく実装する話ですが、実は割と惜しいところまでいってましたね。

reg_matchesでvectorのdataを渡したはずなのにout of rangeなのは1点目のメモリ管理の話なので省きますが、
vector<string>を渡すバージョンの方ではメモリ管理はvectorがしてくれるのと、
マッチした結果を取得する実装自体は問題なさそうです。

さてこれをHSPのプラグインとして実行したときにエラーになる件ですが、
エラーの内容通り単純にcode_setvaで代入しようとしたときに対象の変数の配列長を超えてアクセスしたためです。

配列アクセスする際はプラグイン側で配列の添え字をチェックする必要がありますが、
今回は代入なので代入前に必要な配列長の確保をする必要があります。

配列確保には通常HspVarCoreDimを使いますが、文字列はFlexタイプ(各要素サイズが可変)の型なのでHspVarCoreDimFlexを使う
…と言いたいところですが、これは宣言だけあり定義がないので、最終的にexinfo->HspFunc_dimが正解です、下記のように。


exinfo->HspFunc_dim(pval, HSPVAR_FLAG_STR, 1, len, max_length, 0, 0);// STRの場合は動的に各要素が拡張されるので、サイズを指定する必要はない

※今更ですがHSPSDKは完成されたものではないので、この辺は空気を読んでOpenHSPを漁るなり自分で探す必要があります………。

――――――――――
それとですが、そもそもreg_matchesをどういう機能にしたいのかこのスレッドで述べてないですよね?
具体的にどういうケースを投げるとどういう結果になるべきかも示されておらず、
仕様がない状態で”どうすればよいでしょうか?”と聞かれても答えられません。

また、ご自分でテストケースを書いて結果を共有する姿勢は素晴らしいですが、
テストケースについてもどういった事を意図したもので具体的にどういうコードであるかが分からなければ、
独りよがりな主張以外の何物でもありません。

せめてDropBoxのzipの方にテストケースを含めるなど、途中から参加した方やここだけ見れば分かる、
程度に物事の流れをまとめておくべきでしょう。

…と書くと流石に意地悪すぎるのでここまでにしておきますが、
ある程度相談内容は焦点を絞り、コードは透過的にしておかないとツッコミできないことについてはご留意ください。

さてそれはそうと、こちらが示すサンプル実装ではmod_regex.asにあるmatchesの引数3つバージョンをreg_matchesとして再実装することにしました。

ディレクトリ階層はそのままで、直下にサンプル実装をReleaseでビルドしたhspregexp.dllとreg_matchesのテスト用のコードtest.hspを、
hspregexpには差分のあるmain.cppやmain.h、main2.cppのみ含めてあります。
※蛇足ですが、DLしたソリューションのhsp_statは定義されてなかったのでstatに書き直してます、必要に応じて再変更をお願いします。

https://firestorage.jp/download/974ac67c69c4ae251043feb2a061e4f3382ed671
password= hsp90002

DLしたディレクトリで該当ファイルを上書きすればビルド通ってtest.hspも通ると思いますが、
差分等足りてない箇所はツッコミもらえればと思います。

…あとこれも蛇足ですが、pdbファイルなどはローカルでのデバッグ目的でVisualC++が自動生成するシンボルファイルで、
ローカルのファイルパスも含まれていますので配布にはご注意を。



kanamaru

リンク

2020/4/25(Sat) 19:22:20|NO.90187

ありがとうございます。なかなか時間が取れず、細かい部分の検証ができずにいました。
ダウンロードして実行してみました。
想定していた実行結果が出ていて、驚きました。
言われてみれば、想定している動作について説明していなかったようです。
最終的にはhsp本家のmod_regexp.asと同じ動作にするつもりでした。
メモリ管理については知識が足らず、迷惑をおかけしました。
プログラムから良そうしている人もいるとは思いますが、
本家にはない命令を追加する予定です。
先述した通り、時間が取れない状態です。(具体的には就活中です)
時間が取れ次第、メモリ管理について勉強し、
メモリ管理についてきちんと理解してから開発を再開したいと思います。
このスレッドは解決済みにしておきます。
メモリ管理について勉強が終わったら、新しくスレッドを作ろうと思います。
最後になりますが、今回はご迷惑をおかけして本当にすいませんでした。



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