const nel linguaggio C consente di limitare la modificabilità di un oggetto. Quando si lavora con i parametri delle funzioni, ciò aiuta a proteggere i dati da modifiche accidentali. La principale differenza nella dichiarazione dipende da a cosa si riferisce il modificatore const e dove si trova rispetto al puntatore.
Esempio di varie dichiarazioni:
void func(const int *ptr); // puntatore a un int costante void func(int * const ptr); // puntatore costante a un int void func(const int *const ptr); // puntatore costante a un int costante
const int *ptr — i dati non possono essere modificati, il puntatore può essere riassegnato.int *const ptr — i dati possono essere modificati, ma il puntatore non può essere riassegnato.const int *const ptr — né i dati né il puntatore possono essere modificati all'interno della funzione.Uso corretto di const: consente di:
void print_array(const int *arr, size_t n) { for (size_t i = 0; i < n; ++i) { printf("%d\n", arr[i]); // arr[i] = 10; // errore: tentativo di modificare dati const } }
Domanda: Può essere assegnato l'indirizzo di una variabile costante a un puntatore normale?
Risposta errata attesa: "Sì, se si rimuove const nella dichiarazione del puntatore, il compilatore lo consente."
Risposta corretta: È consentita la "riduzione di const" solo con esplicita conversione di tipi (casting), ma questo porta a un undefined behavior se si tenta di modificare un oggetto dichiarato come const. Non è possibile farlo: viola la semantica di const e porta a errori di runtime.
Esempio:
const int x = 5; int *ptr = (int*)&x; *ptr = 10; // UB: modifica dell'oggetto const
Storia
In un grande progetto, un programmatore ha cercato di eludere la protezione const, castando un puntatore const a uno normale e modificando i dati nella sezione di memoria read-only. Su alcune piattaforme ciò ha portato all'arresto anomalo del programma (segmentation fault), su altre — a errori silenziosi, difficili da debug.
Storia
In una libreria per lavorare con gli array, lo sviluppatore ha dimenticato di dichiarare i parametri come const. Di conseguenza, una chiamata di funzione errata ha accidentalmente modificato i dati originali, causando la desincronizzazione dello stato dell'array e seri bug nei successivi blocchi di elaborazione.
Storia
Durante la scrittura di una funzione di callback, passata a una libreria esterna, è stato dimenticato di specificare const per il buffer di ingresso. La libreria ha provato a modificare i dati in una stringa costante, causando crash su alcuni sistemi operativi e lunghe indagini sull'origine del problema.