La prima è l'utilizzo della parola chiave register nella definizione di una variabile.
La parola register suggerisce al compilatore che la variabile verrà utilizzata spesso, e per questo è meglio mantenerla a portata di mano su un registro della CPU invece di doverla recuperare ogni volta dalla memoria RAM.
La definizione di una variabile register è elementare:
register int nomeVariabile;
Bisogna però dire che non sempre sono disponibili dei registri della CPU, oppure il compilatore si accorge che effettivamente la variabile non è utilizzata così tanto da giustificare l'occupazione di un registro: in questi casi il compilatore ignora la parola chiave register.
Dall'altro lato il compilatore è in grado di ottimizzare il codice e decidere autonomamente quali varibili mantenere nei registri e quando farlo, quindi di fatto è meglio non utilizzare la parola chiave register e lasciare che sia il compilatore a gestire il codice nel migliore dei modi.
L'altra cosa che ho tralasciato sono le funzioni inline.
Normalmente una funzione risiede in un'area della RAM che in teoria potrebbe essere molto distante dall'area in cui risiede la parte di codice dove la funzione viene richiamata.
Ad esempio:
void funzione()Nel nostro esempio la funzione funzione() potrebbe trovarsi molto distante in memoria dalla funzione main().
{
cout << "CIAO! SONO IL CORPO DELLA FUNZIONE! ";
}
int main()
{
funzione();
return 0;
}
In questo caso, quando all'interno della funzione main() viene richiamata funzione(), la CPU deve muoversi dall'area di memoria in cui è memorizzato il codice di main() all'area in cui è memorizzato il codice di funzione().
Questo salto da un punto all'altro della RAM implica un certo spreco di risorse e può rallentare l'esecuzione del programma.
Se invece dichiariamo la funzione come inline, al momento della compilazione il compilatore sostituirà letteralmente la chiamata a funzione() con il corpo della funzione stessa, così al momento dell'esecuzione del codice della funzione, questo si troverà esattamente all'interno dell'area di memoria in cui è situata la funzione main(), con un certo risparmio di risorse hardware.
Da un punto di vista visuale questo codice:
inline void funzione()equivale a:
{
cout << "CIAO! SONO IL CORPO DELLA FUNZIONE! ";
}
int main()
{
funzione();
return 0;
}
int main()Dove la chiamata a funzione è stata sostituita dal corpo della funzione.
{
{
cout << "CIAO! SONO IL CORPO DELLA FUNZIONE! ";
}
return 0;
}
La parola chiave volatile invece ha a che fare con le costanti.
Quando creaiamo una costante con la parola chiave const diciamo al compilatore che il valore di quella costante non cambierà mai.
Perciò se all'interno del programma accediamo spesso alla costante, il compilatore la mette temporaneamente in un registro della CPU così che la CPU stessa non debba accedere alla memoria RAM ogni volta che le serve il valore memorizzato nella costante.
Questo può succedere perché il valore contenuto dalla costante sarà sempre lo stesso, quindi non c'è pericolo che, mentre una copia del dato è memorizzata in un registro della CPU, il dato originale in RAM venga modificato. Non c'è pericolo quindi che la copia all'interno del registro non sia aggiornata.
Esistono però casi in cui un valore dev'essere costante all'interno del programma, e cioé non può essere modificato dal programma stesso, ma può essere modificato da altri programmi o dall'hardware.
Ad esempio immaginiamo un programma che ricava l'ora da un orologio esterno collegato al computer. Non vogliamo che il programma per sbaglio modifichi l'orario, perciò dichiariamo costante il puntatore che punta alla locazione in cui l'orologio salva l'ora. Tuttavia l'orario viene modificato continuamente dall'esterno, e cioè dall'orologio stesso, e rischiamo che il compilatore, pensando che il dato sia immutabile, metta una copia dell'orario all'interno di un registro della CPU e, quando controlliamo l'orario tramite il nostro programma, questo ci mostra la copia non aggiornata presente nel registro, invece di quella attuale.
Per ovviare a questo utilizziamo la parola chiave volatile, che avverte il compilatore del fatto che, benché il programma stesso non possa modificare l'area di memoria puntata dal puntatore, è possibile che questa venga modificata da altri programmi o dall'hardware. In questo modo il compilatore eviterà di ottimizzare il codice copiandolo in un registro della CPU, e lo terrà in memoria RAM dove sarà sempre aggiornato.
Per finire tratto brevemente un'altra parola chiave, che però non spiegherò nei dettagli (forse lo farò in futuro), e cioè la parola extern.
La parola extern, fatta precedere ad una variabile all'interno di un blocco di codice, indica che quella variabile non è locale ma si riferisce ad una variabile esterna al blocco:
int var1;
void funzione()
{
extern int var1; //si riferisce alla variabile var1 dichiarata fuori dal blocco della funzione
}
Nessun commento:
Posta un commento