2010-07-30 7 views
8

FINAL EDIT: Sembra infatti essere un bug del compilatore - vedere la risposta accettata.VBA: Che cosa sta causando questo argomento stringa passato a ParamArray per essere modificato in un numero (che sembra sospettosamente come un puntatore)?

Utilizzando VBA all'interno di Excel 2007, ho il seguente codice in '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 

e un po 'di codice in modalità in un modulo:

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 

Se chiamata 'esterno' dalla immediata finestra come questa:

call outer(array("a")) 

torno di uscita che sembra strano:

0.123.516,410617 millions
102085832 
a 
a 
a 

Sembra che sia importante sapere se la routine chiamata si trova in un modulo di classe o meno, se si tratta di una Sub o di una Funzione e se esiste o meno un argomento iniziale. Mi manca qualcosa su come VBA dovrebbe funzionare? Qualche idea?

Lo strano numero cambia da esecuzione a corsa. Dico "guarda con sospetto, come un puntatore", perché se io chiamo questo:

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 

in questo modo:

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

torno uscita come:

101788312 
101788328 
101788344 

E 'l'incremento del 16 questo mi rende sospettoso, ma davvero non lo so. Inoltre, passando un valore, dite chiamando:

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

funziona bene.

EDIT: Un po 'più informazioni ... Se assegno il valore restituito da 'c.strange' a qualcosa, invece di buttarlo via, ottengo lo stesso comportamento:

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 

È interessante notare che, se io chiama le mie routine di test come sopra, con un argomento che risulta dal chiamare 'Array', il valore del puntatore presunto cambia. Tuttavia, se lo chiamo in questo modo:

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

Ricevo lo stesso numero, anche se faccio ripetutamente la chiamata. (Il numero cambia se passo a un'altra app in Windows, come il mio browser.) Quindi, ora sono incuriosito dal fatto che l'analizzatore di Excel (invocato con le parentesi) apparentemente memorizza nella cache i suoi risultati ...

risposta

5

Ora questo è fantastico .

Riprodotto per ufficio 2003.
Sembra un bug del compilatore.

Il problema è in questa linea:

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

Qui il compilatore crea un Variant che contiene una matrice di 1D Variant 's, l'unico elemento di cui è un puntatore invece del valore.Questo puntatore quindi passa alla funzione strange che in realtà non è strana, stampa solo il valore Variant\Long passato ad esso.

Questo trucco porta la sanità mentale compilatore posteriore:

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

EDIT

Sì, questo numero magico è un puntatore alla struttura VARIANT che dovrebbe essere passato al metodo strange. Il primo campo di cui è 8, che è vbString, e il campo dati contiene un puntatore alla stringa effettiva "a".

Pertanto, è sicuramente un compilatore bug ... Ancora un altro compilatore VB bug nei confronti degli array;)

+0

Sì, sembra come un insetto. Solo qualche strano caso limite ... ParamArray, in una funzione, in una classe, con un altro parametro in primo piano, ecc .... @GSerg, hai qualche conoscenza interna del compilatore VBA? – jtolle

+0

Cosa succede se lo chiami come «ret = c.strange (" ", v (LBound (v)))» invece di usare Call? – ninjalj

+0

@ninjalj, l'ho provato, e ho ottenuto lo stesso comportamento. – jtolle