Un semplice metodo per scrivere codice pił sicuro in C/C++. Il qualificatore const e il suo uso per evitare involontarie modifiche delle informazioni.
Per rendere piu' sicuro il proprio codice a volte non sono necessari complessi stratagemmi o ingegnosi trucchi, anzi, spesso bastano pochi accorgimenti. Un problema comune della programmazione e' quello di utilizzare i propri dati senza pero' modificarli, bisogna cioe' mantenere l'integrita' delle informazioni ma al contempo tentare di processarle il piu' velocemente possibile.
Il linguaggio C utilizza il passaggio di argomenti per copia, cio' significa che quando passiamo un parametro alla funzione viene sempre generata una copia della variabile passata che sara' utilizzata solo all'interno della funzione. Questo assicura l'integrita' delle nostre informazioni.
Per esempio nel seguente codice la variabile i non viene mai modificata da increment().
#include stdio.h
void increment(int value);
int main(int argc, char *argv[])
{
int i = 5;
increment(i);
printf("i = %d \n", i);
return 0;
}
/* La variabile value e' semplicemente una copia della variabile i del programma
principale. */
void increment(int value)
{
value++;
}
L'output sara':
i = 5
Il problema si pone quando dobbiamo trattare dati di grandi dimensioni come strutture e array dove non possiamo accettare il costo delle operazioni di copia degli argomenti. E' qui che entrano in gioco i puntatori che sono al contempo la potenza e il punto debole del C, la gioia e l'agonia del programmatore.
Per esempio la semplice funzione stringLen mostra il passaggio di un puntatore, un array di char, a una funzione. Cio' ci permette di aumentare notevolmente le prestazioni poiche' viene passato alla funzione solamente l'indirizzo dell'array ma mette in discussione il concetto di integrita' dei dati. Infatti passando il puntatore e non piu' una copia della variabile le eventuali modifiche apportate all'interno della funzione si ripercuotono anche sul programma principale. Per esempio la funzione di libreria che deve manipolare l'array potrebbe accidentalmente modificare l'argomento passato (basti pensare a una funzione molto complessa).
Il seguente codice presenta un esempio del programma client e di due implementazioni della funzione stringLen, una esegue solo le operazioni previste, l'altra modifica anche i dati in ingresso:
#include stdio.h
/* Prototipo della funzione */
int stringLen(char* string);
/* Programma Client */
int main(int argc, char *argv[])
{
char stringa[10] = {"Ciauz"};
printf("Lunghezza stringa = %d \n", stringLen(stringa));
printf("Stringa: %s \n", stringa);
return 0;
}
Ecco la versione corretta:
int stringLen(char* string)
{
int i = 0;
while(string[i] != '\0')
   i++;
return i;
}
L'output del programma:
Lunghezza stringa = 5
Stringa: Ciauz
Ecco la versione che modifica l'array:
int stringLen(char* string)
{
int i = 0;
while(string[i] != '\0') {
   string[i]++;
   i++;
   }
return i;
}
L'output non e' certo quello voluto:
Lunghezza stringa = 5
Stringa: Djbv{
Quindi il programma client non puo' sapere con certezza se la propria variabile originaria sara' modificata o meno. E' proprio per risolvere tale problema che il linguaggio C offre la possibilita' di utilizzare il qualificatore Const, una novita' introdotta dallo standard ANSI.
Quando una variabile e' preceduta dal valore const significa che essa, dopo essere stata inizializzata con un valore, non potra' piu' essere modificata, rimarra' cioe' costante per tutta la durata del programma.
Tramite const e' possibile specificare nei parametri della funzione che l'argomento non sara' oggetto di modifica.
int stringLen(const char* string);
int stringLen(const char* string)
{
int i = 0;
while(string[i] != '\0')
   i++;
return i;
}
In questo modo il programma client e' assolutamente sicuro che i valori contenuti nella variabile passata alla funzione non saranno modificati e al contempo le prestazioni sono ottime.
Inoltre poiche' la variabile e' definita const in certe occasioni l'accesso a tale variabile sara' piu' rapido poiche' il compilatore sa che non cambiera' mai di valore.
Questo dichiarazione di funzione e' utile anche allo sviluppatore della funzione di libreria che puo' accorgersi di un accidentale tentativo di modifica durante la stesura del codice in quanto il compilatore genera un errore (tentativo di scrittura su un memoria di sola lettura) durante la compilazione. E' inoltre un buon metodo per autodocumentare la propria funzione.
no
char f(list_of_lists *ll) {
char result = NON_DEC_LENGTHS + NON_DEC_SUMS;
int maxlen = -1;
int maxsum = INT_MIN;
for(; ll != NULL; ll = ll->next) {
if(ll->val == NULL) continue;
list *curlist = ll->val;
int curlen = list_length(curlist);
if(curlen < maxlen) result &= ~NON_DEC_LENGTHS; else maxlen = curlen;
int cursum = 0;
for(; curlist; curlist = curlist->next) {
cursum += curlist->val;
}
if(cursum < maxsum) result &= ~NON_DEC_SUMS; else maxsum = cursum;
}
return result;
}
Re: complimenti & tipo const
Grazie per i complimenti! E per la correzione!
Commenti e correzioni sono sempre ben accetti.
complimenti
bel lavoro
Risponditipo const
da correggere: ...Quando una variabile e preceduta dal valore const siggnifica che la essa... il resto OK.