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