ここでは整数型1次元配列について考えていくことにします。
※整数型以外だととってもややこしい(?)ので省略します。
2次元以上の配列の場合は忘れてしまいました。
すんません(^_^;)。
整数型1次元配列の内容は、メモリには以下のようにならんでいます。
AD HA(0)の内容(下位 1 バイト) AD+1 HA(0)の内容(上位 1 バイト) AD+2 HA(1)の内容(下位 1 バイト) AD+3 HA(1)の内容(上位 1 バイト) AD+4 HA(2)の内容(下位 1 バイト) AD+5 HA(2)の内容(上位 1 バイト) ......ここでADは配列の先頭アドレス(= HA(0)の中身のある場所)、HA(n)は配列変数です。 つまり、HA(n)の内容はAD + (n × 2)にその下位1バイトが、AD + (n × 2) +1に上位1バイトが入るわけです。
そこで、配列の先頭アドレスをマシン語に渡す方法を考えてみましょう。 ユーザーが決めたアドレスに先頭アドレスを書き込む方法も考えられますが、ここはひとつスマートにUSR関数の引数として渡す方法を考えてみましょう。
BASICにはVARPTR(variable pointer:「バリアブルポインター」と読みます)という関数が用意されています。
これは、指定した変数の内容が収められているアドレスを返すものです。例えば、
PRINT VARPTR(P%)
とすると、変数P%のアドレスがモニタに出力されます(マイナス値が出てくる場合は、それを16進化するか、65536を加えたものがアドレスとなります)。
さて、配列の先頭アドレスもやっぱりVARPTR関数で求めることができます。
VARPTR(HA(0))
という感じで。
ただ、それをUSR関数の引数として渡すには注意が必要です。
以下、サンプルプログラムをば。
10 CLEAR200,&HCFFF 20 DEFINT A−Z 30 RESTORE1000:AD=&HD000 40 READ D$:IF D$=”*” THEN ELSE POKE AD,VAL(”&H”+D$):AD=AD+1: GOTO40’マシンご プログラム スタンバイ 50 DEFUSR=&HD000 60 DIM A(15) 70 A(0)=2480 80 B=VARPTR(A(0)):C=USR(B) 90 PRINT C 100 END 1000 DATA 23,23,5E,23,56,2B,EB ,ED,A0,ED,A0,C9,*10行でマシン語領域を確保しています。
I=USR(5)とすると、変数Iには5番地の内容+6番地の内容×256が入ります。 ソースコードは以下のようになっています。
ORG 0D000H INC HL INC HL LD E,(HL) INC HL LD D,(HL) DEC HL EX DE,HL LDI LDI RET ENDマシン語でUSR関数の引数の読み方や返り値の書き方が分からない人のために補足説明をします。 まずUSR関数で呼ばれた時、HLレジスタには引数のあるアドレスが入っているので(HL+2に下位1バイト、HL+3に上位1バイトが入っています)、そこをチェックしてやればいいです。 返り値は引数の入っていた場所に返したい値を書き込んでやればいいです。
80 B=VARPTR(A(0)):C=USR(B)70行でA(0)に2480という値を入れています。 80行ではまず、変数Bに配列A(n)の先頭アドレス、つまりA(0)の内容があるアドレスを代入しています。 次に、このBをマシン語プログラムの引数としてUSR関数を実行しています。 返り値CにはB番地の内容が入ります。
どうやら、80行のUSR関数の引数として渡した値は、配列A(n)の先頭アドレス(= A(0)のアドレス)ではなく、全然関係のない場所の中身が(変数Cに)返ってきてしまったようです。
でも、引数で渡したのは確かにA(0)のアドレスだったはず、それを変数Bに入れて引数として渡し…。
実はそこに落し穴があったのです。
BASICの変数、特に配列変数は、何か命令を実行すると、その記憶場所が変わることが多いようなのです。
HB-F1XDJ付属のBASIC文法書のVARPTRの所にも、変数に値を代入した地点で変数の番地が変わるということが書かれています。
サンプルプログラムの80行でも、VARPTR関数で得られた配列A(n)の先頭アドレスを一旦変数Bに格納し、それからUSR関数の引数として渡していますね。
このたった2つの命令の間で、配列A(n)の記憶場所が変わってしまったのです。
ですから、変数Bを引数として USR関数を使っても、その場所(変数Bが示すアドレス)には既に配列A(n)はなく、全然関係のない値を返してしまったというわけです。
BASICってせわしないやつだねぇ。
サンプルプログラムの80行を次のように変えて実行すると、今度はモニタにちゃんと「2480」と出力されます。
80 C=USR(VARPTR(A(0)))VARPTR関数でアドレスを得てすぐに使ってしまおうというわけです。