-
前回はバイナリサーチ(SEARCH.FN3)の紹介を行いましたが、 この検索では1個のコードに対して処理する機能しかありません。
コードは昇順にしないとバイナリサーチは利用できないので、 1レコードの中に複数コードが存在しソートできない場合などのデータファイルの場合には利用できません。
複数コードの条件付けを行い検索できるのが、拡張関数の サーチ処理関数(SEARCH.FN3) です。 今回はこの拡張関数について説明します。
■サーチ処理関数(SEARCH.FN3)について
この関数は以下の4個の機能があります。
機能番号 処理内容 .fcAndSrch 1 「AND」サーチ(レコード番号検索) .fcOrSrch 2 「OR」サーチ(レコード番号検索) .fcAndSrchN 11 「AND」サーチ件数(件数のみ検索) .fcOrSrchN 12 「OR」サーチ件数(件数のみ検索)
「レコード番号検索」と「件数のみ検索」で関数に渡す引数の書式が異なります。
[書式1] CALL "SEARCH.FN3" .fcAndSrch FILENO%, RSTART, REND, RECORD, STRING1$, STRING2$... RSTART, REND, RECORD は、整数型(%),長整数型(&),実数型(指定無し)が使用可能 [書式2] CALL "SEARCH.FN3" .fcAndSrch FILENO%, RSTART, REND, RECORD, STRING$(), STRINGN% RSTART, REND, RECORD は、整数型(%),長整数型(&),実数型(指定無し)が使用可能 <引き数> .fcAndSrch:機能番号指定 FILENO% :ファイル番号 RSTART :検索開始レコード番号 REND :検索終了レコード番号 FIELDNO% :フィールド番号 STRINGn$ :検索条件 STRING$() :検索条件(配列指定時) STRINGN% :検索条件数(配列指定時) STRINGn$やSTRING$()は「検索方法」+「フィールド番号」+「検索文字列」で指定します。 「検索方法」、「フィールド番号」は数値を「CHR$関数」で文字列化 <戻り値> RECORDNO :検索結果(レコード番号) ・RECORDNO には、検索条件に一致するデータが見つかったレコード番号が返されます。 見つからなかった場合、0 が返されます。 ・RECORDNO は、整数型の最大値(32767)を超える場合あるので、 変数に代入する場合、長整数型変数か実数型変数を推奨します
今回の検索関数を使用する例のために以下の様なデータファイルを想定します。 これは今まで使ってきたTEST.DATに削除フラグを追加しています。 ファイル名はTEST2.DATとします。
項目名 フィールド長 内容 品番 16 商品コードの文字列 数量 12 商品の数量を文字列で格納 削除フラグ 1 "1":削除済み 、 "0"削除されていない
サーチ処理関数(SEARCH.FN3) を使う上で OR条件 よりも AND条件 を 使う方が多いと思うので、 AND条件 を例にとります。
品番と削除フラグの AND条件 でデータファイル( TEST2.DAT )を検索する 関数が以下の様になります。関数コールの書式は検索条件に文字列配列を使った「書式2」で行っています。
'--------------------------------------- 'データ検索その2 '--------------------------------------- 'Function MfSearchData2%(Byval pstrCD$, Byval pintDel%, Byref plngNum&, Byref plngRecNo&) '引 数: ' pstrCD$ :コード ' pintDel% :削除フラグ ' pdblVal$ :数量 ' plngRecNo& :レコードNO '戻り値: ' MfSearchData2% :読込OK:GcTrue%, NG:GcFalse% '--------------------------------------- Function MfSearchData2%(Byval pstrCD$, Byval pintDel%, Byref plngNum&, Byref plngRecNo&) 'エラー処理宣言 On Error Goto MfSearchData2.ErrProc 'フィールドサイズ(既に宣言済み) ' Const COL.CD% = 16 ' Const COL.NUM% = 12 ' Const COL.DEL% = 1 '戻り値の初期化 MfSearchData2% = GcFalse% 'FIELD関連変数 PRIVATE FILENO%, REC.CD$, REC.NUM$, REC.DEL$ 'TEST.DAT2ファイルを、ファイル番号#1としてオープンします FILENO% = 1 OPEN GcTEST2.DAT$ AS FILENO% RECORD 2147483647 FIELD #FILENO%, COL.CD% AS REC.CD$, COL.NUM% AS REC.NUM$, COL.DEL% AS REC.DEL$ '検索データの整形 PRIVATE WK.CD$, WK.DEL$ WK.CD$ = LEFT$(pstrCD$ + GfSpc$(COL.CD%), COL.CD%) If pintDel% = GcTrue% Then WK.DEL$ = "1" Else WK.DEL$ = "0" EndIf 'レコードNO検索 PRIVATE RSTART&, REND&, RECORDNO&, STRING$(2)[64], STRINGN% RSTART& = 1 REND& = LOF(FILENO%) 'ファイルの最後まで検索 STRINGN% = 2 '検索条件配列の個数 STRING$(0) = CHR$(0) + CHR$(1) + WK.CD$ '検索条件(=条件),フィールド番号(1:場所CD) STRING$(1) = CHR$(0) + CHR$(3) + WK.DEL$ '検索条件(=条件),フィールド番号(3:削除フラグ) CALL "SEARCH.FN3" .fcAndSrch FILENO%, RSTART&, REND&, RECORDNO&, STRING$(), STRINGN% If RECORDNO& > 0 Then 'レコードNOが返された場合,レコードの取得 GET FILENO%, RECORDNO& '数値文字列を返す plngNum& = VAL(REC.NUM$) plngRecNo& = RECORDNO& '正常を返す MfSearchData2% = GcTrue% Endif MfSearchData2.Return '関数戻り If FILENO% > 0 Then Close FILENO% Endif On Error Goto 0 Exit Function '----- 'エラー処理 '----- MfSearchData2.ErrProc MfSearchData2% = GcFalse% Resume MfSearchData2.Return End Function
■検索関数の利用上記の検索関数の動作をテストするソースを以下に記します。
SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 '最初は書き込み処理の連続 PRIVATE W% W% = MfPutData2%("CD0001", 100, GcTrue%, 0) W% = MfPutData2%("CD0002", 102, GcFalse%, 0) W% = MfPutData2%("CD0003", 1030, GcTrue%, 0) W% = MfPutData2%("CD0101", 201, GcTrue%, 0) W% = MfPutData2%("CD0201", 202, GcFalse%, 0) W% = MfPutData2%("CD1001", 500, GcTrue%, 0) PRIVATE CD$, RNO&, NUM& CD$ = "CD0001" '削除ONで検索⇒検索OK W% = MfSearchData2%(CD$, GcTrue%, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF CD$ = "CD0002" '削除ONで検索⇒検索NG W% = MfSearchData2%(CD$, GcTrue%, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF CD$ = "CD0002" '削除OFFで検索⇒検索OK W% = MfSearchData2%(CD$, GcFalse%, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF CD$ = "CD0201" '削除OFFで検索⇒検索OK W% = MfSearchData2%(CD$, GcFalse%, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF WAIT 0, &h01 'キー入力待ち END
最初のテストデータの書き込みで使っている関数 MfPutData2% は、下の方にソースがありますのでそちらを参照下さい。 また、これによって作成された TEST2.DAT は以下の図の様になります。(デバッガ上でのシミュレーションでのファイル参照ですが)
品番コードと削除フラグの指定を合わせて検索しています。
このソースの実行結果は以下の図の様になります。
関数 MfPutData2% のソースです。
Const GcTEST2.DAT$ = "TEST2.DAT" '--------------------------------------- 'データ書込(TEST2.DAT) '--------------------------------------- 'Function MfPutData2%(Byval pstrCD$, Byval plngNum&, Byval pintDel%, Byval plngRecNo&) '引 数: ' pstrCD$ :コード ' plngNum& :数量 ' pintDel% :削除フラグ ' plngRecNo& :レコードNO(0:レコード追加) '戻り値: ' MfPutData2% :書込OK:GcTrue%, NG:GcFalse% '--------------------------------------- Function MfPutData2%(Byval pstrCD$, Byval plngNum&, Byval pintDel%, Byval plngRecNo&) 'エラー処理宣言 On Error Goto MfPutData2.ErrProc 'フィールドサイズ Const COL.CD% = 16 Const COL.NUM% = 12 Const COL.DEL% = 1 '戻り値の初期化 MfPutData2% = GcFalse% PRIVATE FILENO%, REC.CD$, REC.NUM$, REC.DEL$ FILENO% = 0 'TEST.DAT2ファイルを、ファイル番号#1としてオープンします FILENO% = 1 OPEN GcTEST2.DAT$ AS FILENO% RECORD 2147483647 FIELD #FILENO%, COL.CD% AS REC.CD$, COL.NUM% AS REC.NUM$, COL.DEL% AS REC.DEL$ 'フィールドへデータ設定 REC.CD$ = LEFT$(pstrCD$ + GfSpc$(COL.CD%), COL.CD%) '既定の桁数分スペースを付加 REC.NUM$ = RIGHT$(GfSpc$(COL.NUM%) + STR$(plngNum&), COL.NUM%) '既定の桁数分スペースを付加 REC.DEL$ = "0" If pintDel% = GcTrue% Then REC.DEL$ = "1" Endif If plngRecNo& = 0 Then 'レコードNOが0の場合,レコードの最後尾に追加 PUT FILENO% Else 'レコードNOが指定された場合,レコードの上書 PUT FILENO%, plngRecNo& Endif '正常を返す MfPutData2% = GcTrue% MfPutData2.Return '関数戻り If FILENO% > 0 Then Close FILENO% Endif On Error Goto 0 Exit Function '----- 'エラー処理 '----- MfPutData2.ErrProc Resume MfPutData2.Return End Function
=====
2016/04/02:の時の情報
PR -
マスタデータファイルを検索する場合によく使われるバイナリサーチがあります。 バイナリサーチとは日本語では二分検索と言われるもので、 プログラマの方ならば説明の必要もないぐらい一般的なものだと思います。
前提条件として検索対象となるコードを、昇順ソートしてファイルに登録しておきます。
バイナリサーチでは最初に先頭レコード(左側)と最終レコード(右側)の中央に位置するコードが、 検索コードより大きいかまたは、小さいかを比較します。
中央のコードが大きい場合は、中央の位置を次の処理の右側とします。 また、中央のコードが小さい場合は、中央の位置を次の処理の左側とします。 再度、左側と右側の中央の位置を求めて、中央のコードと検索コードの比較を行います。
これを繰り返すことで領域を狭めていき最終的に目的のコードが見つかるまで行います。 (結果的に見つからない場合もありますが)
これらの一連の処理を BSEARCH.FN3 は行っています。■バイナリサーチ処理関数(BSEARCH.FN3)についてCALL "BSEARCH.FN3" .fcBSrcOp FILENO%, FIELDNO%, STRING$, RECORDNO <引き数> .fcBSrcOp: オープンされているファイルのバイナリサーチ指定 FILENO% : ファイル番号 FIELDNO%: フィールド番号 STRING$ : 検索文字列 FILENUM%: 検索ファイル数 <戻り値> RECORDNO:検索結果(レコード番号) ・RECORDNO には、検索条件に一致するデータが見つかったレコード番号が返されます。 見つからなかった場合、0 が返されます。 ・RECORDNO は、整数型の最大値(32767)を超える場合あるので、 変数に代入する場合、長整数型変数か実数型変数を推奨します
オープンされていないファイルのサーチもできるのですが、検索した結果、対象のレコードデータを 取得して何かの処理を行うのが普通だと思いますので、オープン済みファイルが対象のものだけを扱います。
それではこれを使った検索の関数をテストデータファイルを例に使ったものが以下に様になります。
'--------------------------------------- 'データバイナリ検索 '--------------------------------------- 'Function MfBSearchData%(Byval pstrCD$, Byref plngNum&, Byref plngRecNo&) '引 数: ' pstrCD$ :コード文字列 ' plngNum& :数値を返す ' plngRecNo& :レコードNOを返す '戻り値: ' MfBSearchData% :検索OK:GcTrue%, NG:GcFalse% '--------------------------------------- Function MfBSearchData%(Byval pstrCD$, Byref plngNum&, Byref plngRecNo&) 'エラー処理宣言 On Error Goto MfBSearchData.ErrProc ' Const COL.CD% = 10 '[MfPutData%]で定義済み ' Const COL.NUM% = 26 '戻り値の初期化 MfBSearchData% = GcFalse% plngRecNo& = 0 PRIVATE FILENO%, FIELDNO%, STRING$, RECORDNO&, REC.CD$, REC.NUM$ 'TEST.DATファイルを、ファイル番号#1としてオープンします FILENO% = 1 OPEN GcTEST.DAT$ AS FILENO% RECORD 2147483647 FIELD #FILENO%, COL.CD% AS REC.CD$, COL.NUM% AS REC.NUM$ '検索文字列を既定の桁数分スペースを付加 REC.CD$ = LEFT$(pstrCD$ + GfSpc$(COL.CD%), COL.CD%) '既定の桁数分スペースを付加 FIELDNO% = 1 'バイナリ検索 CALL "BSEARCH.FN3" .fcBSrcOp FILENO%, FIELDNO%, REC.CD$, RECORDNO& If RECORDNO& > 0 Then 'レコードNOが返された場合,レコードの取得 GET FILENO%, RECORDNO& '数値文字列を返す plngNum& = VAL(REC.NUM$) plngRecNo& = RECORDNO& '正常を返す MfBSearchData% = GcTrue% Endif MfBSearchData.Return '関数戻り If FILENO% > 0 Then Close FILENO% Endif On Error Goto 0 Exit Function '----- 'エラー処理 '----- MfBSearchData.ErrProc plngNum& = 0 Resume MfBSearchData.Return End Function
■検索関数の利用上記の検索関数の動作をテストするソースを以下に記します。
SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 '最初は書き込み処理の連続 W% = MfPutData%("CD0001", 100, 0) W% = MfPutData%("CD0002", 102, 0) W% = MfPutData%("CD0003", 1030, 0) W% = MfPutData%("CD0101", 201, 0) W% = MfPutData%("CD0201", 202, 0) W% = MfPutData%("CD1001", 500, 0) 'バイナリサーチでの検索各種 PRIVATE CD$, RNO&, NUM& CD$ = "CD0101" W% = MfBSearchData%(CD$, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF CD$ = "CD0003" W% = MfBSearchData%(CD$, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF CD$ = "CD0002" W% = MfBSearchData%(CD$, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF 'コードを発見できない検索 CD$ = "CD0005" W% = MfBSearchData%(CD$, NUM&, RNO&) IF W% = GcTrue% THEN PRINT CD$ + "(" + STR$(RNO&) + "):" + STR$(NUM&) ELSE PRINT CD$ + ":Not Found" ENDIF WAIT 0, &h01 'キー入力待ち END
最初のテストデータの書き込みは、コードが重複せずに昇順に行っています。 このファイルはマスタデータとして考えていますので、コードの重複はあり得ません。
尚、ユーザ関数 MfPutData% は以下の記事にありますので、参照して下さい。
BHT-BASIC4.0:データファイルの取り扱いについてその2(書込み・読込みの実用的な関数)
バイナリサーチの3番目まではレコードの内容を読めていますが、 4番目のコード"CD0005"はテストデータ書込みで行っていないので レコードは検索できません。
このソースの実行結果は以下の図の様になります。
=====
2016/04/02:の時の情報
-
前回使用した拡張関数 ファイル情報提供関数(FILE.FN3) を利用して、 データファイルの存在確認を行う関数を作ってみます。
尚、この拡張関数の1番目の機能である .fcInfGetF(指定されたファイルの情報の獲得) を 使いますが、これの説明は以下の記事にありますので、参照して下さい。
データファイルの削除等について(KILL、CLFILEのラッパ関数)
この拡張関数を使用した、ファイル存在確認関数は以下の様になります。
'--------------------------------------- 'ファイル存在チェック関数 '--------------------------------------- 'Function GfFileExist%(Byval pstrFileName$) '引 数: ' pstrFileName$:ファイル名 '戻り値: ' GfFileExist% :存在OK:GcTrue%, NG:GcFalse% '--------------------------------------- Function GfFileExist%(Byval pstrFileName$) 'エラー処理宣言 On Error Goto GfFileExist.ErrProc Private INF$ INF$ = GfSpc$(40) ' 40 文字分の領域を確保 CALL "FILE.FN3" .fcInfGetF pstrFileName$,INF$ If INF$ = "" Then 'NULL文字はファイルが存在しない GfIsNum% = GcFalse% Else GfIsNum% = GcTrue% End If GfFileExist.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfFileExist.ErrProc GfFileExist% = GcFalse% Resume GfFileExist.Return End Function
ファイル情報の結果が返される文字列変数(INF$)の内容がNULLであれば、ファイルが存在しないことを示しています。
=====
2016/04/02:の時の情報
-
データファイルのファイル削除やレコード削除を行う場合、 その都度 KILL命令 や CLFILE命令 を実行するよりも ラッパ関数を作って、それをコールする方がソース的にすっきりすると思います。
■KILL命令のラッパ関数についてKILL命令の定義は以下の様です。KILL <ファイル名> <ファイル名>:"[ドライブ名:]ファイル名[<S>]"の書式の文字列式 ("ファイル名"は"ファイル名称"+"."+"拡張子")
KILL命令のラッパ関数は以下の様になります。
'--------------------------------------- 'ファイル削除(KILL命令のラップ) '--------------------------------------- 'Function GfKill%(Byval pstrFileName$) '引 数: ' pstrFileName$ :ファイル名 '--------------------------------------- Function GfKill%(Byval pstrFileName$) 'エラー処理宣言 On Error Goto GfKill.ErrProc '戻り値の初期化 GfKill% = GcFalse% '指定ファイル名の削除 KILL pstrFileName$ GfKill% = GcTrue% GfKill.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfKill.ErrProc Resume GfKill.Return End Function
エラー処理は何もしていませんが、ここでエラー内容などを表示するといいと思います。
■CLFILE命令のラッパ関数についてデータファイルに書き込む関数を以下の様に定義します。
CLFILE命令の定義は以下の様です。CLFILE [#]<ファイル番号> <ファイル番号>:1~16の値を返す数値式 (OPEN命令で指定したファイル番号を指定)
CLFILE命令のラッパ関数は以下の様になります。
'--------------------------------------- 'ファイルレコード削除(CLFILE命令のラップ) '--------------------------------------- 'Function GfClFile%() '--------------------------------------- Function GfClFile% 'エラー処理宣言 On Error Goto GfClFile.ErrProc 'フィールドサイズ ' Const COL.CD% = 10 '上の関数[MfPutData%]で定義済み ' Const COL.NUM% = 26 '戻り値の初期化 GfClFile% = GcFalse% PRIVATE FILENO%, REC.CD$, REC.NUM$ 'TEST.DATファイルを、ファイル番号#1としてオープンします FILENO% = 1 OPEN GcTEST.DAT$ AS FILENO% RECORD 2147483647 FIELD #FILENO%, COL.CD% AS REC.CD$, COL.NUM% AS REC.NUM$ 'レコード削除 CLFILE #FILENO% GfClFile% = GcTrue% GfClFile.Return '関数戻り If FILENO% > 0 Then Close FILENO% Endif On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfClFile.ErrProc Resume GfClFile.Return End Function
この関数は、"TEST.DAT"ファイルのレコード削除しかできない関数をラップしたものです。
FIELD命令はフィールド変数を固定でしか宣言できないのでこの様な感じになりました。 この部分を汎用性を持たせるのは少し大変なので、固定でもいいかなと思います。 方法が無いことは無いのですが、やはりFIELD命令がネックになります。
以下の関数は無理やり汎用性を持たせたCLFILE命令のラッパ関数です。
'--------------------------------------- 'ファイルレコード削除(CLFILE命令のラップ) '--------------------------------------- 'Function GfClFile2%(Byval pstrFileName$) '引 数: ' pstrFileName$ :ファイル名 '--------------------------------------- Function GfClFile2%(Byval pstrFile$) 'エラー処理宣言 On Error Goto GfClFile2.ErrProc '戻り値の初期化 GfClFile2% = GcFalse% 'ファイル情報提供関数(FILE.FN3)の利用 PRIVATE INF$, FieldNum%, I%, FSZ%(16) '40 文字分の領域を確保 INF$ = " " CALL "FILE.FN3" .fcInfGetF pstrFile$,INF$ FieldNum% = ASC(MID$(INF$, 22, 1)) ' フィールド数の獲得 FOR I% = 1 TO 16 '各フィールド幅の取得 FSZ%(I%) = ASC(MID$(INF$, 22 + I%, 1)) NEXT PRIVATE FILENO%, W$ '指定ファイルを、ファイル番号#1としてオープンします FILENO% = 1 OPEN pstrFile$ AS FILENO% RECORD 2147483647 'フィールド定義をフィールド数毎に分けて処理 SELECT FieldNum% CASE 1 FIELD #FILENO%, FSZ%(1) AS W$ CASE 2 FIELD #FILENO%, FSZ%(1) AS W$, FSZ%(2) AS W$ CASE 3 FIELD #FILENO%, FSZ%(1) AS W$, FSZ%(2) AS W$, FSZ%(3) AS W$ CASE 4 FIELD #FILENO%, FSZ%(1) AS W$, FSZ%(2) AS W$, FSZ%(3) AS W$, FSZ%(4) AS W$ CASE 5 FIELD #FILENO%, FSZ%(1) AS W$, FSZ%(2) AS W$, FSZ%(3) AS W$, FSZ%(4) AS W$, FSZ%(5) AS W$ CASE 6 FIELD #FILENO%, FSZ%(1) AS W$, FSZ%(2) AS W$, FSZ%(3) AS W$, FSZ%(4) AS W$, FSZ%(5) AS W$, FSZ%(6) AS W$ '....(この後必要な分作成???) END SELECT 'レコード削除 CLFILE #FILENO% GfClFile2% = GcTrue% GfClFile2.Return '関数戻り If FILENO% > 0 Then Close FILENO% Endif On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfClFile2.ErrProc Resume GfClFile2.Return End Function
ファイルのフィールド数、各フィールド幅の取得を行う為に、 拡張関数の "FILE.FN3" を使用しています。
CALL "FILE.FN3" .fcInfGetF FILENAME$, INF$ FILENAME$:ファイル名 INF$:ファイル情報が返される(40 文字、または、ヌル文字) (必ず40 バイト以上の領域を確保しておく)
INF$の内容は以下の通りです。
位置 文字数 データ内容 値 1 12 ファイル名 文字列 13 2 (システムリザーブ) - 15 2 最大レコード数 1~32767 17 2 レコード数 1~32767 19 2 1クラスタあたりのレコード数 0 21 1 レコード長 1~255 22 1 フィールド数 1~16 23 16 各フィールドのフィールド幅 1~254 39 2 (システムリザーブ) -
=====
2016/04/02:の時の情報
-
ユーザ関数の引数の仮変数を普通の変数の様に使用することができます。 但し、文字列型変数の場合文字列長に関して注意する点があります。
今回は仮のユーザ関数として以下の様なものを宣言します。
'--------------------------------------- '引き数の仮変数のテスト '--------------------------------------- 'Sub MsTest(Byval pstrCD$) '引 数: ' pstrCD$ :コード '--------------------------------------- Sub MsTest(Byval pstrCD$) 'エラー処理宣言 On Error Goto MsTest.ErrProc '3文字を設定 pstrCD$ = "123" PRINT "3文字を設定:" + pstrCD$ '4文字を設定 pstrCD$ = "1234" PRINT "4文字を設定:" + pstrCD$ '5文字を設定 pstrCD$ = "12345" PRINT "5文字を設定:" + pstrCD$ MsTest.Return '関数戻り On Error Goto 0 Exit Sub MsTest.ErrProc 'エラー発生時にエラーコード表示 PRINT "ERR=" + RIGHT$("00" + HEX$(ERR), 2) Resume MsTest.Return End Sub
この関数は仮変数である pstrCD$ に3文字~5文字までのテストデータを代入し 単にその内容を表示しています。
尚、エラー処理では発生したエラーコードを表示させています。
上記の関数の動作をテストするソースを以下に記します。
SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 PRIVATE W$ W$ = "0001" '4文字データを代入 CALL MsTest(W$) '4文字データの変数の値を渡す WAIT 0, &h01 'キー入力待ち END
関数 MsTest の中でブレークポイントを設定し pstrCD$ の 内容を表示させてみます。 以下の図は MsTest に制御が移った直後の pstrCD$ ですが 文字列のサイズが4文字になっています。
呼出し元の変数 W$ はサイズが40文字のはずですが、 引き数としては4文字になっています。
さらにステップ実行すると以下の図になります。 pstrCD$ に"123"が設定されている様子です。
そのまま実行を継続すると、以下の図の表示なります。
5文字の設定のところでエラーが発生し、エラーコードが 0F(16進数) と表示されます。 このエラー内容は 「文字列長が範囲外です。」 です。
※結果的に、ユーザ関数の引数の文字列型仮変数に代入する場合は文字列長に注意が必要だということになります。
=====
2016/04/02:の時の情報