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


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
0906
Lisa重複した範囲の dupptr について6解決


Lisa

リンク

2011/9/6(Tue) 22:38:02|NO.41141

こんにちは。
dupptrについて分からないことがあるので教えてください。

ある大きなバッファ(メモリ)を複数の変数に割り当てたいのですが、
重複した範囲を指定すると期待通りになりません。

[0][1][2][3][4][5][6][7][8][9]
というメモリブロックがあったとき、
変数 p1 には [0] 〜 [9] を
変数 p2 には [4] 〜 [9] を
変数 p3 には [8] 〜 [9] を割り当てたいと思っています。


txt = "0123456789" ptr = varptr(txt) dupptr p1, ptr + 0, 10, 2 dupptr p2, ptr + 4, 6, 2 dupptr p3, ptr + 8, 2, 2 mes "p1 = " + p1 + "\np2 = " + p2 + "\np3 = " + p3 + "\n" p2 = "++" mes "p1 = " + p1 + "\np2 = " + p2 + "\np3 = " + p3 + "\n" repeat 10 mes strf("txt.%2d = %c", cnt + 1, peek(txt, cnt)) loop

これを実行して頂くと、p3 の内容がクリアされていることが分かります。
p1 は 0123++<NULL>
p2 は ++<NULL>
になるのはOKなのですが、
p3 は 89 のまま、という動作を期待しています。
([0][1][2][3][+][+][NULL][7][8][9]であって欲しい)

間違っていることなどありますでしょうか?
よろしくお願いします。



この記事に返信する


check

リンク

2011/9/6(Tue) 22:45:44|NO.41143

それはもうHSPの仕様なのではないだろうか。
クローン変数に値を代入することはクローンもとの変数も書き換えることになるので、
おそらく"++"という文字列を単純に代入してクローン元を書き換えているのではなく、
メモリの再確保などの動作が内部では行われているのではないだろうか。

そんなめんどくさいことはせずに素直に文字列操作系の命令を使ったらどうだろうか。



Lisa

リンク

2011/9/6(Tue) 23:11:49|NO.41151

checkさん、ありがとうございます。

> クローン変数に値を代入することはクローンもとの変数も書き換えることになるので、
> おそらく"++"という文字列を単純に代入してクローン元を書き換えているのではなく、
> メモリの再確保などの動作が内部では行われているのではないだろうか。

dupptr のヘルプに
「クローン変数は、指し示しているメモリの位置が変更されてもそれを検知することはできません。」
とありましたので、
単純にアドレスだけを考慮してHSPの変数として扱えるようにしてるのでは、と考えました。

ちなみに、「書き換える」というのではなく「同一メモリ」を操作していると思っていたのですが、
間違っていますか?

> そんなめんどくさいことはせずに素直に文字列操作系の命令を使ったらどうだろうか。

元のバッファは HSP 内で確保したものではなく、別アプリで確保したものです。
(具体的には C++製のアプリ内で作成したメモリマップドファイルです)

大きなバッファが必要なときは[0] 〜 [9] の範囲で自由に使えるようにし、
小さなバッファが2つ必要なときは[0] 〜 [4] と [5] 〜 [9] で分割して使えるように
したいと思っています。

・・・で、いちいち dupptr で割り当てるのが設計上 困難なので、
[0] 〜 [9] と [5] 〜 [9] を用意し、
前者の場合は [0] 〜 [9] を割り当てた変数を使い、
後者の場合は [0] 〜 [9] と [5] 〜 [9] の変数の両方を使うというようなことが
できないかと思い、現在この問題に直面しています。

このようなことを「文字列操作系の命令」でできるのでしょうか?
よろしくお願いします。



レノス

リンク

2011/9/7(Wed) 03:11:08|NO.41163

poke 命令を用いるとできます。

poke p2, 0, "++"

> 〜という動作を期待しています。
p2 = "++" という代入は、文字列変数として p2 の値を "++" に置き換えているので、
"++" の後ろがどうなってしまうかは全く保障されないのが自然です。
p2 の3バイト目以降が何であろうと、( p2 == "++" ) が成立するため。

# なにも0埋めしなくても、とは思いますが

メモリ操作命令である poke は、型と関係なく、“変数が持つメモリに値を書き込む処理”なので、
このような動作になります。


それと蛇足ですが
> クローン変数に値を代入することはクローンもとの変数も書き換えることになるので、
> おそらく"++"という文字列を単純に代入してクローン元を書き換えているのではなく、
> メモリの再確保などの動作が内部では行われているのではないだろうか。
dupptr は参照先がHSPが管理するバッファか否かを考えていないので、
クローン変数を操作しても、それは"どこかのメモリ"を操作するのと同じで、
クローン元の変数が変数として処理されることはありません (文字列や配列の自動拡張など)。
※現行の実装では。



木村

リンク

2011/9/7(Wed) 16:33:48|NO.41165

 memcpy命令を用いてみるのはいかがでしょうか。以下は一例

txt = "0123456789" ptr = varptr(txt) dupptr p1, ptr + 0, 10, 2 dupptr p2, ptr + 4, 6, 2 dupptr p3, ptr + 8, 2, 2 mes "p1 = " + p1 + "\np2 = " + p2 + "\np3 = " + p3 + "\n" //修正部分 plus = "++" memcpy p2, plus, strlen(plus)+1, 0, 0 ; p2 = "++" mes "p1 = " + p1 + "\np2 = " + p2 + "\np3 = " + p3 + "\n" repeat 10 mes strf("txt.%2d = %c", cnt + 1, peek(txt, cnt)) loop

 汎用性を高める意味で上記修正部分をユーザー定義命令に書き換えるならこんな感じになるでしょう。

#module #deffunc memwrite str mem, var ptr, local vm vm = mem memcpy ptr, vm, strlen(vm)+1, 0, 0 return #global



Lisa

リンク

2011/9/7(Wed) 20:04:32|NO.41192

レノスさん、木村さん、ありがとうございます。
文字列操作ではなく、メモリ操作することで解決できそうです!

> poke 命令を用いるとできます。

poke 命令は1文字しか書き込めないために不適切だと思っていたのですが、
文字列も使用できるんですね、知りませんでした。

poke 命令を用いることでちゃんと期待通りの結果になりました。

何度も繰り返すわけではありませんので、今回は関係ないのですが、
dupptr に代入する処理は約2.140ミリ秒に対し、poke は約2.570ミリ秒と大差ありませんでした。
(1KBの文字列使用、1000回ループで確認。)

> memcpy命令を用いてみるのはいかがでしょうか

memcpy 命令でも期待通りの結果になりました。
こちらは strlen 込みで、2.340ミリ秒となりました。


しかも、poke でも memcpy でも指定位置に書き込めますので、
dupptr を使うのは最初の1回で済みそうです。

みなさんどうもありがとうございました!

(環境:Win7 32bit 3GHz 2GB)



Lisa

リンク

2011/9/7(Wed) 20:38:07|NO.41196

※追記です


b = str(a) poke b, 0, str(a) tmp = str(a) memcpy b, tmp, strlen(tmp), 0, 0

memcpyは高速なのですが、
変数 a が数値ではない可能性を考えると、別の変数に一度代入する必要があり、
代入処理を挟むと一番遅くなってしまいました。

しかし今回は速度を気にしないので memcpyを使うことにしました。
(名前が一番用途にあっていますので)



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