' Rapid-Q by William Yu (c)1999-2000 . ' ================================================================================ ' Upload_il_tuo_script_su_Rapidq.it ' Capitolo_11__Utilizzo_dei_puntatori_alle_funzioni ****** 11. Utilizzo dei puntatori alle funzioni ****** Siete sorpresi di trovare puntatori alle funzioni in un linguaggio di programmazione BASIC? Bene, in Rapid-Q i puntatori alle funzioni sono un pò diversi da quelli a cui siamo abituati. Immagino che alcune cose siano un pò strane, ma le cose più importanti sono presenti, come la ridefinizione di puntatori alle funzioni ed i puntatori alle funzioni dinamici. Sfortunatamente (almeno fino a questo momento) non è possibile passare puntatori alle funzioni come argomenti. 11.1 Introduzione al concetto Cosa sono i puntatori alle funzioni? So che molti sono stanchi della terminologia, solo perchè probabilmente la definizione è molto più facile da capire. E' utile comprendere come i dati vengono memorizzati e identificati in memoria. Ad esempio, una funzione (cioè SUB o FUNCTION) occupa dello spazio ad un determinato indirizzo. Un puntatore a detta funzione non è altro che il suo indirizzo. Così se si conosce l'indirizzo della funzione è possibile saltare nello "spazio di elaborazione" ed eseguire il codice ivi contenuto. Questo è un modo di pensare di basso livello, prima spingere i parametri e poi saltare (cioè chiamare) alla funzione. Dunque, se i puntatori sono solo numeri, come si determina l'indirizzo della funzione? A questa domanda risponderemo qui di seguito. 11.2 Definire i puntatori alle funzioni Se avete un'esperienza precedente con i puntatori (ad es. in C) dovrete abituarvi ad alcune differenze. In Rapid-Q, dal momento che i puntatori sono numeri, è possibile utilizzare qualunque tipo di dato numerico per definirli. Sembra strano, ma i puntatori sono solo numeri. E' meglio evitare BYTE, dal momento che l'indirizzo della vostra funziona può essere maggiore di 255, e BYTE può non essere sufficiente. Suggerisco di utilizzare INTEGER/LONG. DECLARE SUB Test (I AS INTEGER) DIM FPtr AS INTEGER BIND FPtr TO Test Bene, in Rapid-Q utilizziamo BIND per associare la nostra variabile FPtr alla funzione Test. Questo servirà a due cose: ovviamente FPtr punterà all'indirizzo di Test, ma stabilisce anche il numero di parametri per FPtr, e questo è importante per il compilatore per sapere quanti parametri passare o accettare. Per chiamare nostra funzione, dobbiamo utilizzare il comando CALLFUNC: CALLFUNC(FPtr, 120) In questo modo chiamiamo la nostra SUB Test con un parametro. Ovviamente questo esempio non è molto utile; consideriamone un altro... DECLARE SUB Test1 (I AS INTEGER) DECLARE SUB Test2 (I AS INTEGER) DIM FPtr(1 TO 2) AS INTEGER BIND FPtr(1) TO Test1 BIND FPtr(2) TO Test2 Notate che quando vengono associate delle matrici la prima funzione associata sarà lo schema per tutti gli altri elementi. Siete confusi? Bene, diciamolo in parole più comprensibili. :) La nostra matrice è FPtr, e BIND associa FPtr(1) a SUB Test1. FPtr è ora BOUND (associato). Questo significa che se viene associato qualunque altro FPtr (i), la funzione DEVE AVERE LO STESSO NUMERO DI PARAMETRI. Forse un esempio sarà di aiuto: DECLARE SUB Test1 (I AS INTEGER) DECLARE SUB Test2 (I AS INTEGER, J AS STRING) DIM FPtr(1 TO 2) AS INTEGER BIND FPtr(1) TO Test1 BIND FPtr(2) TO Test2 Il secondo BIND è errato, in quanto Test2 non ha gli stessi parametri di Test1. Se farete questo riceverete un messaggio di errore. Notate che ho parlato di stesso NUMERO di parametri, non è necessario che siano dello stesso tipo. Non fatelo comunque, i risultati possono essere incerti. 11.3 Utilizzo corretto di puntatori alle funzioni Quando avrete utilizzato puntatori alle funzioni per un certo tempo sarà chiaro che a volte il loro utilizzo è necessario, altre volte no. Penso che ogni situazione sia diversa, ma considerate questa: SELECT CASE I CASE 1 Process1("1", 44) CASE 2 Process2("2", 55) CASE 3 Process3("3", 66) CASE 4 : : etc... Potete generalizzare questa situazione, ad esempio un menù con diverse opzioni, o un programma di analisi (Rapid-Q utilizza puntatori alle funzioni per analizzare il vostro codice). Come avrete notato, ci sono diverse comparazioni, soprattutto se state scrivendo un analizzatore con molte parole chiave (più di 50). È possibile eliminare facilmente queste comparazioni utilizzando puntatori di funzione, accelerando così il vostro programma. Per un esempio concreto vedi FUNCPTR.BAS. BIND FPtr(1) AS Process1 BIND FPtr(2) AS Process2 BIND FPtr(3) AS Process3 BIND FPtr(4) AS Process4 BIND FPtr(5) AS Process5 BIND FPtr(6) AS Process6 BIND FPtr(7) AS Process7 x = VAL(INPUT$(1)) CALLFUNC(FPtr(x), 33) Il codice che vedete non è eseguibile così com'è, ma penso che renda l'idea. In nessun caso avremo bisogno di dichiarazioni di questo tipo (purché abbiate partizionato i vostri puntatori correttamente). 11.4 Cosa non supporta Rapid-Q I puntatori alle funzioni come argomenti non sono supportati. Anche se può sembrare ridicolo, in realtà è una cosa molto utile. Sfortunatamente non ho ancora avuto l'opportunità di implementarlo. È possibile passare il valore del puntatore come argomento, ma come vedete non potrete chiamare la vostra funzione. L'unico modo sarebbe definire un puntatore ad una funzione globale come schema, e successivamente assegnarlo al vostro argomento. Sono più chiaro con un esempio: DECLARE FUNCTION MyFuncTemp (X AS LONG) AS LONG DECLARE FUNCTION Func1 (X AS LONG) AS LONG DECLARE FUNCTION Func2 (X AS LONG) AS LONG DIM Template AS INTEGER DIM I(100) AS INTEGER BIND Template TO MyFuncTemp BIND I(1) TO Func1 BIND I(2) TO Func2 SUB Test (FPtr AS INTEGER) Template = FPtr PRINT CALLFUNC(Template, 10) END SUB Test I(1) Questo è l'unico modo per superare questa limitazione. ' =============================================================================== ' 2003 Holyguard.net - 2007_Abruzzoweb