ページ 1 / 1
配列の引渡し
Posted: 2005年9月26日(月) 16:51
by H
コード: 全て選択
#strict
Dim a[1,1]=[[1,2],[3,4]] As Byte
dim lpa As VoidPtr
lpa=VarPtr(a)
Z(a)
End
Sub Z(ByVal a[1,1] As Byte)
dim lpa As VoidPtr
dim a0 As byte
lpa=VarPtr(a)
debug
a0=a[0,1] ←アクセス違反
End Sub
上記プログラムをコンパイルした時点で
[警告] "Z"の第1パラメータが、*ByteからByteに強制変換されています。
となります
実行するとZ内のlpaはa[0,0]の値が返ります
- a配列(&H12FFBC)
[0,0]16
[0,1]0
[1,0]0
[1,1]0
lpa 16
a0 0
グローバル値は
- a配列(&H407010)
[0,0]1
[0,1]2
[1,0]3
[1,1]4
lpa 4222992(&H407010)
追記
Posted: 2005年9月26日(月) 17:00
by H
AB4.10.00です
前のVERSION(4.04)に戻しても同様になってしまいました
4.10にする前の4.04では、Z内のA配列の値は同様ですが
動作的には問題なしです
Posted: 2005年9月27日(火) 01:07
by マティ
どのような処理を行いたいのか分かりませんが・・・
普通の処理言語では、値渡しで配列全体の内容や配列の形状を送る事はできません。
もし、引数のa[0,1]と同じ値を参照するプログラムを作ると
コード: 全て選択
#strict
Dim a[1,1]=[[1,2],[3,4]] As Byte
Z(a)
End
Sub Z(a As BytePtr)
dim a0 as byte
a0=a[0*2+1] 'この計算式が重要
End Sub
動作の説明
ローカル変数で参照するのは、関数Zを呼び出すさいにセットしたグローバル変数のアドレスです。
指定した配列を元に計算を行ったアドレスが存在しない場合は、もちろんエラーで落ちます。(運が良ければ動作したりします)
先頭のアドレスしか渡せないので、配列の格納位置計算は自分でします。
実はABには特別な仕様があって、構造を含めた関数コールが可能であったら教えて下さい。
Posted: 2005年9月27日(火) 14:03
by イグトランス
> 実はABには特別な仕様があって、構造を含めた関数コールが可能であったら教えて下さい。
Hさんのコード自体がそうです。
http://www.discoversoft.net/help_center ... ameter.htm
ここの「多次元配列をパラメータとして引き渡すには」に書いてあります。
Hさんのコードではグローバル変数とZの引数のaをLongなどにすればアクセス違反は発生しませんでした。
ほか、16/32bit整数型では全て問題ありませんでしたが、Charと浮動小数点型はだめでした。
64bit整数型は元のZでは問題ありませんでしたが、そこへa[0, 0]~a[1, 1]を画面へ出力するようにしたところ、
画面に出力が見えた直後にアクセス違反で落ちてしまいました。
ちなみにアクセス違反が起きない際にはlpa = VarPtr(a[0, 0])とすればグローバル変数の値とZのローカル変数の値は一致します。
Posted: 2005年9月28日(水) 23:23
by H
返信ありがとうございます
説明不足でした
Z関数内でのa配列の参照ポインタの場所が違うのではとの疑問だったのですが・・・
(上記コードは検証用に作成したものです)
イグトランスさんにならって、再度検証したところ
デバッグ時のlpaの値 → 続行クリック
(ローカル)
8bit:&H78 → アクセス違反
16bit:&H5678 → アクセス違反
32bit:&H12345678 → 正常終了
64bit:&H12345678 → 正常終了*1
*1 ただし64bit型ではENDをはずすと、アクセス違反が発生します
*2 lpaのグローバル値は&H12345678です
*3 ヘルプセンターのサンプルプログラムでも検証しようとしたのですが
うまくいきませんでした(デバッグでストール状態)
なお、現在配列の仮引数はByValになっていますが
ByRefの方がわかりやすいと思うのですがいかがでしょう
以上、調査および検討をお願いします
Posted: 2005年9月29日(木) 23:37
by マティ
イグトランスさんありがとうございます。非常に勉強になりました。
ところで、パラメータの参照方法に、引数が値参照(By Value)を指定すると配列、構造体を値参照することはできません。
とありますので、今回の回答は、ByRefを指定して下さいが正解でしょうか?
Posted: 2005年9月30日(金) 20:27
by イグトランス
> とありますので、今回の回答は、ByRefを指定して下さいが正解でしょうか?
それがそうでもないのです。やってみるとわかりますが、
「配列ポインタを引渡すときは、値参照(ByVal)にしてください」
というエラーになります。
つまり配列をByRefではなく配列へのポインタをByValでという考えになっているようです。
前に示したURLでも全てByVal/ByRefの指定を省略しているのでByVal扱いとなっていますね。
Posted: 2005年9月30日(金) 23:21
by マティ
すみません!現象を理解できないので
これはABのコンパイラエラーメッセージのバグではなく、仕様と言うことでしょうか?
配列や、構造体を値渡し(ByVal)するようなことは、絶対にはありえないと思います。(というか実装できるのですか?)
山本様
値渡しで構造体や配列を渡す事は不可能(勝手な推測)なので正しい仕様をお教え下さい。
Posted: 2005年10月01日(土) 09:25
by イグトランス
> 配列や、構造体を値渡し(ByVal)するようなことは、絶対にはありえないと思います。(というか実装できるのですか?)
>
山本様
> 値渡しで構造体や配列を渡す事は不可能(
勝手な推測)なので正しい仕様をお教え下さい。
私はもちろん山本様ではありませんが、勝手ながら書かせてもらいます。
あれは構文上配列をByValとなっていますが、実際にはポインタをByVal渡しするようです。
前に示したURLのページにも次のようなことが書かれてあります。
この引き渡し方法は、具体的には配列のポインタのみを引き渡しています。
ところでC/C++では構造体・クラスを値渡しで引数、戻り値に指定できます。(引数に構造体・クラスの値渡しは推奨されていませんが)
配列では値渡しだと引数の場合にはポインタに読み替えられ、戻り値にはできません。(参照渡しはCになくC++で導入されたので配列の参照渡しはできますがほとんど使われていません)
ABが配列をByValと指定するのはこの「引数の型を配列の値渡しと指定するとポインタの値渡しにコンパイラが読み替える」というC/C++の仕様を模倣したためと私は思っています。
たしかにABの配列をByVal指定する仕様はいまいち馴染まないような感じがします。
しかしながらByValを明示して書くからそう感じるだけで、省略してしまえば大して気にならないとも思っています。
Posted: 2005年10月01日(土) 11:38
by マティ
イグトランスさんの説明で
理解しました。
大昔に、オブジェクト仕様を習った際、関数を準備する側が全ての変数に対応できるようにする義務があるような話だったので、
C++系は全く勉強していませんでした。
ついでに原因も分かりましたので報告します。
コード: 全て選択
Dim a[1,1]=[[1,2],[3,4]] As Byte
配列をこの形で初期化すると、だめなようです!
プログラムでデータを設定すると大丈夫でした。
Posted: 2005年10月02日(日) 17:44
by ゲスト
>
ついでに原因も分かりましたので報告します。
>
コード: 全て選択
> Dim a[1,1]=[[1,2],[3,4]] As Byte
>
> 配列をこの形で初期化すると、だめなようです!
> プログラムでデータを設定すると大丈夫でした。
相変わらずうまくいかないです
やはり、ポインタ参照位置おかしくないですか?
配列の初期化については、
こちらをみてください
Posted: 2005年10月03日(月) 13:31
by マティ
私の勘違いでした!!!ABのバグのようです!
Hさんの
lpaの考察通り、関数に配列のアドレスを渡せないのが原因でした!
8bit -> アドレスの下位1バイトのみ転送
16bit -> アドレスの下位2バイトのみ転送
32bit -> アドレスが全て渡るのでOK
となっていました!
山本様へ
配列渡しや構造体渡しは、ByRef型にした方が良いとおもいませんか?
#strict
を強化する際の障害になって行くような気がします。
PS.私の
実験結果はたまたま動いていたみたいです。