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


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
0419
TNK構造体のようなもの11解決


TNK

リンク

2015/4/19(Sun) 06:55:17|NO.68646

ほんとう何度も質問して申し訳ありません。
相変わらずマニュアルを読んでもよく分からないんです。

1:
なんでもいいので構造体の「ようなもの」はないでしょうか?
様々なものをまとめて取り扱いたいです。

2:
あと、配列を配列のまま取り扱えるのは、
#defcfuncのプロトタイプ(のようなもの)で、arrayを指定した物の送受信のみでしょうか?
他にもなにかあるでしょうか?

3:
あと、ポインタや、類似する手段がないことも確認したいです。



すみません、うざいかもしれませんがプログラム自体の構造に影響するんで早めに知っておきたいんです。



この記事に返信する


ht_ask

リンク

2015/4/19(Sun) 08:30:27|NO.68647

> 1:
> なんでもいいので構造体の「ようなもの」はないでしょうか?
> 様々なものをまとめて取り扱いたいです。

一番近いのはモジュール変数ですが、OOPの用語でいえばアクセサメソッドが必須で、
メソッド名がグローバル名前空間を汚すので構造体としてはかなり使いにくいです。
というわけで、主にはメンバの数だけ配列を用意して並べるしかありません。
非公式のプラグインの中には構造体やコンテナなどのデータ型をHSPに追加するものもあります。

> 2:
> あと、配列を配列のまま取り扱えるのは、
> #defcfuncのプロトタイプ(のようなもの)で、arrayを指定した物の送受信のみでしょうか?
> 他にもなにかあるでしょうか?

HSPの配列の実体はCと同じ連続領域なので、その要領でクローン変数を利用して参照を行うことはできます。

a = 1, 2, 3 dup b, a dupptr c, varptr(a), length(a) * 4, 4 mes a(0) mes b(1) mes c(2)

> 3:
> あと、ポインタや、類似する手段がないことも確認したいです。

前述のとおり、しいて言えばクローン変数がそれです。
varptrとdupptrを組み合わせることでポインタのアクセスと同じことができます。
あとは、#deffuncの型名にvarを指定することで参照的な振舞いをすることはすでにご存知だと思います。

> すみません、うざいかもしれませんがプログラム自体の構造に影響するんで早めに知っておきたいんです。

淡々と進む問答は回答していても気分がいいので僕は歓迎です。



TNK

リンク

2015/4/19(Sun) 16:10:54|NO.68651

丁寧にご回答ありがとうございます。
教えて頂いたので少し色々やってみましたが、そのうちいくつか質問させて下さい。

trd1 = 1, 2, 3
trd2 = 10, 20, 30

scd(0) = varptr(trd1)
scd(1) = varptr(trd2)

fst(0) = varptr(scd)
fst(1) = varptr ;;....略

もしこうゆうような使い方をする場合、
この書き方は問題が発生しますか?
アドレスが変わる事があるとか書かれていたので、やはりダメですか?
(変数自体が4次元にまで自動対応してるのは知ってます)。

それと、見落としたのかもしれませんが、
実体へのアクセスのしかたがどこに書いてあるのか分かりませんでした。

a = 100;
b = &a; // varptr(a)
mes *b; // ここはどう書くの?

こうゆう感じに楽なアクセスはできないですか?
もしかして、アクセスする際は絶対クローンが必要ですか?


;;せっかくなんてテストをかねて書いてみる
;;▼階層構造を作る
trd1 = 1, 2, 3
trd2 = 10, 20, 30

dim scd, 16, 2
scd(0,0) = varptr(trd1) ;; (x,0)をポインタ、(x,1)を長さとする
scd(0,1) = length(trd1)
scd(1,0) = varptr(trd2)
scd(1,1) = length(trd2)

dim fst, 16, 2
fst(0,0) = varptr(scd)
fst(0,1) = length2(scd) ;;ここ以降たぶんlength2。よう分からんけど。(適当)

mes "test@scd"
mes scd(0,0)
mes scd(0,1)
mes scd(1,0)
mes scd(1,1)
mes "test@fst"
mes fst(0,0)
mes fst(0,1)
mes ""

;;▼fstからクローンで階層構造にアクセス(逆流)する
dim scd_c, 16, 2,
dupptr scd_c, fst(0,0), fst(0,1) * 4, 4 ;; * 4 がよく分からないけどマネをしておく
mes scd_c ;; scdと同一になるはずなんだけど、scd_c(0,0)がエラーになる。へるぷみー

分からんくなったのでやめました。
と言うかこの方式、色々変数が必要だけどループの中でどうすれば・・・?
頭痛のしない方法を知っていましたらお願いします。

また、関数からもポインタ(アドレス)を取れるようなことが書いてありましたが、
それはどう使うでしょうか。それともそこから関数は実行できないでしょうか
(たとえば配列に関数を入れれたら喜びます)



ht_ask

リンク

2015/4/19(Sun) 19:16:32|NO.68652

> もしこうゆうような使い方をする場合、
> この書き方は問題が発生しますか?
> アドレスが変わる事があるとか書かれていたので、やはりダメですか?

あんまりそういう使い方はしないので、どこまで耐用可能か確信はもてないのですが、
この場合は trd1, trd2 のアドレスが変われば scd は使い物にならなくなり、
scd のアドレスが変われば fst が使えなくなります。

変数のアドレスが変わるタイミングは主に初期化と拡張です。
C++の標準ライブラリのvectorなどをご存知であれば概ね予想がつくと思います。
基本的には、実体となる変数をあらかじめ固定長で確保しておき、
それを超える大きなデータを代入しなければ多分大丈夫です。

trd1 = 1, 2, 3 safe = length(trd1) - 1 repeat 16 trd1(cnt) = cnt + 1 mes "addr:" + varptr(trd1) + " len:" + length(trd1) if cnt = safe : mes "--ここまでは安全--" loop

> もしかして、アクセスする際は絶対クローンが必要ですか?

はい。もともとHSPにポインタという概念はないのですが、
DLLなどを呼び出す際にC互換のデータを扱うことになるので、
HSPのデータ型と仲介するためにvarptrやdupptrの機能があります。
それゆえに、これらの機能は動作保証外であることをお含み置きください。

> fst(0,1) = length2(scd) ;;ここ以降たぶんlength2。よう分からんけど。(適当)

dim scd, 16, 2 と記述したとき、
length(scd) == 16
length2(scd) == 2
ですが、ここは16が格納されるべきところではないですか?

> dim scd_c, 16, 2,

これは特に意味のない記述です。dupptrの前後でvarptr(scd_c)の値は変わるので。

> dupptr scd_c, fst(0,0), fst(0,1) * 4, 4 ;; * 4 がよく分からないけどマネをしておく

第3引数の"4"はHSPの整数型の1個あたりのサイズです。32bitなら4byteです。
第4引数の"4"はvartypeで得られる整数型の識別IDです。ヘルプに載っています。

> mes scd_c ;; scdと同一になるはずなんだけど、scd_c(0,0)がエラーになる。へるぷみー

クローン変数は多次元配列の復元には対応していないようですね。
この方法では一次元配列で作るしかなさそうです。

> と言うかこの方式、色々変数が必要だけどループの中でどうすれば・・・?
> 頭痛のしない方法を知っていましたらお願いします。

「可変長配列の配列」みたいなものを作りたくなったときは、
順当に考えれば否が応にもモジュール変数を使わざるを得なくなると思います。
配列を一個メンバに持ったモジュール型変数、の配列という具合にです。
これも多少の頭痛は避けられないかもしれません。本来的に向いていない処理です。

> また、関数からもポインタ(アドレス)を取れるようなことが書いてありましたが、
> それはどう使うでしょうか。それともそこから関数は実行できないでしょうか
> (たとえば配列に関数を入れれたら喜びます)

関数は無理なので聞き違いだと思いますが、ラベルを変数に代入することはできます。
ラベル型配列を作るにはldimを使用してください。



TNK

リンク

2015/4/19(Sun) 20:52:35|NO.68654

>dim scd, 16, 2 と記述したとき、
> length(scd) == 16
> length2(scd) == 2

あ、lengthの意味が分かりました。
length * length2 で総容量ってことなんですね。

そしてdupptrは多次元には対応してないからlengthを一個しか受け取らないんですね。(たぶん)。


>第3引数の"4"はHSPの整数型の1個あたりのサイズです。32bitなら4byteです。
なるほど。ようやく意味が分かりました。
dupptrは、メモリを共用するスタート位置と終了位置が欲しかったんですね。(たぶん)。

で、私はHSPはvarptrから配列のアドレスが得られるので、
配列を配列としてまとめて扱うための構造があって、そこのアドレスかなんかだと思ってたのですが、
実は別にそうゆうことではなくて、単に高級配列っぽく見せてただけ、みたいな。
勉強になります。
(と言うかdupptrに適当な数値設定したら危なくないですかこれ)


>この方法では一次元配列で作るしかなさそうです。
ポインタと長さはセットにしておかなければならないので、
ちょっと方法が思いつきません。
平行してポインタ用と長さ用の構造を併せて作って、二つをリンクさせながら動作させるとか…?
(いや、それはめんどくさい…!)
そもそも暗黙にアドレスが変わることが理解できたのでこの方法は実験の範囲でやめておくことにします。


>モジュール変数を使わざるを得なくなると思います。
>ラベル型配列を作るにはldimを使用してください。
もっと勉強して色々試してみます。
ありがとうございました。



ht_ask

リンク

2015/4/19(Sun) 21:39:19|NO.68655

> で、私はHSPはvarptrから配列のアドレスが得られるので、
> 配列を配列としてまとめて扱うための構造があって、そこのアドレスかなんかだと思ってたのですが、
> 実は別にそうゆうことではなくて、単に高級配列っぽく見せてただけ、みたいな。

HSPではCと同じように普通の変数は要素数が1つの配列と考えることができます。
Cと異なる点は、内部的にlength〜length3が返す4つの次元データを保持しているところです。
アドレスの値や要素数を観察してみてください。

dim a, 3 mes varptr(a) mes varptr(a.0) mes varptr(a.1) mes varptr(a.2) mes b = 10 mes "b(0)=" + b.0 + " length(b):" + length(b) b.1 = 20 mes "b(1)=" + b.1 + " length(b):" + length(b)

> (と言うかdupptrに適当な数値設定したら危なくないですかこれ)

その通りです。慎重に使わないと知らないデータを破壊するかもしれません。

> ポインタと長さはセットにしておかなければならないので、
> ちょっと方法が思いつきません。

二次元配列をシミュレートするだけですよ。

dim a, 10 * 2 a(0 * 2 + 0) = 00 ; a(0,0) a(0 * 2 + 1) = 01 ; a(0,1) a(5 * 2 + 0) = 50 ; a(5,0) a(5 * 2 + 1) = 51 ; a(5,1)



TNK

リンク

2015/4/19(Sun) 23:03:32|NO.68658

>二次元配列をシミュレートするだけですよ。
なるほどー
一瞬意味が分からなかったけど、数学のロジックと言うやつでしたか…

実はcとかより高級インタプリタとかに慣れてるので、
そうゆうのがピンと思いつかないんですよね。

色々丁寧にありがとうございました。
大変勉強になりました。



osakana

リンク

2015/4/20(Mon) 07:52:54|NO.68662

多次元配列はアドレスの演算で参照することができます。
なおアドレスが並んでいる変数型以外では出来ないので注意。

// 二次元配列を作る(4 * 3) dim a, 4, 3 a(0, 0) = 1, 2, 3, 4 a(0, 1) = 10, 20, 30, 40 a(0, 2) = 100, 200, 300, 400 // 二次元配列の並び // index2 0 1 2 3 // index1 0 1 2 3 0 1 2 3 0 1 2 3 // array [1, 2, 3, 4] [10, 20, 30, 40] [100, 200, 300, 400] // 二次元的に分かりやすく並べると // 0 1 2 3 // 0 [ 1, 2, 3, 4] // 1 [ 10, 20, 30, 40] // 2 [100, 200, 300, 400] // 二次元配列から1次元配列ずつクローンを作って取り出す repeat length2(a) // 一次元分の配列を参照 dupptr cln, varptr(a) + cnt * length(a) * 4, length(a) * 4, 4 repeat length(cln) mes cln(cnt) loop loop



TNK

リンク

2015/4/20(Mon) 10:07:20|NO.68663

ありがとうございます。
HSPがメモリをどう使ってるかドキュメントに明記しない限り、
たぶん実用ではやらないと思うですが…



TNK

リンク

2015/4/21(Tue) 09:56:40|NO.68681

追伸:
もう雑談の部類なのですが、
面白かったのでいろいろテストさせて頂きました。

>アドレスが並んでいる変数型以外では出来ないので注意。
そうゆう変数にテスト中遭遇しなかったのですが、なにか知っていますか?



ht_ask

リンク

2015/4/21(Tue) 18:53:26|NO.68687

たぶん文字列型変数がそれに当たります。
数値型と異なり「文字列型変数はnバイト」という固定長の決め打ちが通用しないので、
おそらく他と違って実体までワンクッションがあると予想できます。
すなわちHSPの文字列型配列は、内部的には「バッファのポインタの配列」になっていて、
varptrはそのポインタの値を参照するので、アドレスが並んでいるという保証がないと見ます。

mes "A いっぺんに初期化した場合" sdim a, 64, 5 repeat length(a) mes varptr(a(cnt)) if cnt > 0 { pos 0, ginfo_cy - ginfo_mesy mes "\t\t増減:" + (varptr(a(cnt)) - varptr(a(cnt - 1))) } loop mes "\nB 動的に初期化した場合" repeat 5 b.cnt = "" + cnt dummy.cnt = "" + cnt ; これがなければ多分Aと同じ条件になる loop repeat length(b) mes varptr(b(cnt)) if cnt > 0 { pos 0, ginfo_cy - ginfo_mesy mes "\t\t増減:" + (varptr(b(cnt)) - varptr(b(cnt - 1))) } loop
ご覧のように、文字列バッファのアドレスは安定しません。



TNK

リンク

2015/4/21(Tue) 20:57:34|NO.68692

そういえば文字列ですね。元から配列なので。
今は調べなければいけないことがいろいろあるので、ひと段落したら仕組みをテストしたいですね。



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