Regole
Fatta questa semplificazione è allora possibile individuare la presenza di anomalie nell’uso delle variabili definendo alcune regole di flusso: alcune di queste devono essere necessariamente rispettate in un programma corretto (1 e 3), mentre altre hanno più a che fare con la semantica dell’uso di un valore (2).
-
L’uso di una variabile deve essere sempre preceduto in ogni sequenza da una definizione senza annullamenti intermedi.
$$ \a\u\err $$
-
La definizione di una variabile deve essere sempre seguita da un uso, prima di un suo annullamento o nuova definizione.
$$ \d\a\err \\ \d\d\err $$
-
L’annullamento di una variabile deve essere sempre seguito da una definizione, prima di un uso o altro annullamento.
$$ \a\a\err $$
Riassumendo, \(\a\op{u}\), \(\d\op{a}\), \(\d\op{d}\) e \(\a\op{a}\) sono sequenze che identificano situazioni anomale, anche se non necessariamente dannose: se per esempio usare una variabile subito dopo averla annullata rende l’esecuzione del programma non controllabile, un annullamento subito dopo una definizione non crea nessun problema a runtime, ma è altresì indice di un possibile errore concettuale.
\(\a\) |
\(\d\) |
\(\u\) |
|
---|---|---|---|
\(\a\) |
\(\Err\) |
\(\Err\) |
|
\(\d\) |
\(\Err\) |
\(\Err\) |
|
\(\u\) |
Esempio
Consideriamo la seguente funzione C con il compito di scambiare il valore di due variabili:
void swap(int &x1, int &x2) {
int x1;
x3 = x1;
x3 = x2;
x2 = x1;
}
Analizzando il codice, le sequenze per ogni variabile sono le seguenti:
Variabile | Sequenza | Anomalie |
---|---|---|
x1 | \(\aR\uR\u\a\) | x1 viene usata 2 volte senza essere stata prima definita |
x2 | \(\dots \d\u\op{d} \dots\) | Nessuna |
x3 | \(\dots \d\dR\opR{d} \dots\) | x3 viene definita più volte senza nel frattempo essere stata usata |
Come si vede, in un codice sintatticamente corretto l’analisi Data Flow ci permette quindi di scovare un errore semantico osservando le sequenze di operazioni sulle sue variabili.