11

最終編集:実際にはコンパイラのバグのようです-受け入れられた回答を参照してください。

Excel 2007 内で VBA を使用すると、「Class1」に次のコードがあります。

Option Explicit

Public Function strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub not_strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Sub

Public Function also_not_strange(ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

モジュール内のいくつかのモードコード:

Option Explicit

Public Function not_strange_either(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub outer(v)
    Dim c As Class1
    Set c = New Class1

    Call c.strange("", v(LBound(v)))
    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

次のようにイミディエイト ウィンドウから「outer」を呼び出す場合:

call outer(array("a"))

奇妙に思える出力が返されます。

 102085832 
a
a
a

呼び出されたルーチンがクラス モジュール内にあるかどうか、Sub か Function か、初期引数があるかどうかが問題のようです。VBA がどのように機能するかについて、何か不足していますか? 何か案は?

奇妙な数は実行ごとに変化します。これを呼び出すと、「疑わしいほどポインタのように見える」と言います。

Public Sub outer2(v)
    Dim c As Class1
    Set c = New Class1

    Dim ind As Long
    For ind = LBound(v) To UBound(v)
        Call c.strange("", v(ind))
    Next ind
End Sub

そのようです:

call outer2(array("a","b","c"))

次のような出力が返されます。

 101788312 
 101788328 
 101788344 

疑わしいのは 16 の増分ですが、実際にはわかりません。また、次のように呼び出して、値を渡します。

Call c.strange("", CStr(v(ind)))

うまく動作します。

編集:もう少し情報...「c.strange」からの戻り値を捨てるのではなく何かに割り当てると、同じ動作が得られます:

Public Sub outer3(v)
    Dim c As Class1
    Set c = New Class1

    Dim x
    x = c.strange("", v(LBound(v)))

    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

興味深いことに、上記のように、'Array' を呼び出した結果の引数を使用してテスト ルーチンを呼び出すと、想定されるポインター値が変更されます。ただし、次のように呼び出すと:

call outer([{1,2,3}])

何度かけても同じ番号にかかってきます。(ブラウザなど、Windowsの別のアプリに切り替えると、数値が変わります。)したがって、Excelエバリュエーター(括弧で呼び出される)が結果をキャッシュしているように見えることに興味をそそられます...

4

1 に答える 1

10

今、これは素晴らしいです。

Office 2003 で再現
。コンパイラのバグのようです。

問題は次の行にあります。

Call c.strange("", v(LBound(v)))

ここで、コンパイラはVariantの 1D 配列を保持するを作成しVariantます。その唯一の要素は、値ではなくポインターです。このポインターは、strange実際には奇妙ではない関数に移動し、Variant\Long渡された値を出力するだけです。

このトリックは、コンパイラの健全性を取り戻します。

Call c.strange("", (v(LBound(v))))

編集

strangeはい、このマジック ナンバーは、メソッドに渡されるはずの VARIANT 構造体へのポインタです。の最初のフィールドは8vbStringあり、データ フィールドには実際の文字列へのポインタが含まれます"a"

したがって、これは間違いなくコンパイラのバグです...配列に関するさらに別の VB コンパイラのバグ ;)

于 2010-07-30T22:05:10.900 に答える