Quando e per quali scopi la parola chiave const dovrebbe essere usata in C per le variabili?


59

Durante la revisione del mio codice qui è emerso il problema dell'utilizzo della constparola chiave. Comprendo che viene utilizzato per l'implementazione del comportamento di sola lettura sulle variabili.

Sono confuso su quali sono le varie situazioni in cui può essere utile.

  • Dovrebbe essere usato per motivi di chiarezza nei prototipi di funzioni?
  • Dovrebbe essere usato come misura di sicurezza durante lo sviluppo del codice?
  • Dovrebbe essere usato nell'ambito di varie funzioni per dichiarare le costanti di runtime?
  • Dovrebbe essere usato affatto?

Queste domande sono solo esempi della confusione che sto affrontando. La confusione generale è

  • Quando dovrebbe essere la constparola chiave utilizzata nella programmazione C?
  • Quali sono i vari tipi di benefici che si possono ottenere usando questa parola chiave in C?
  • Ci sono dei contro nell'uso della constparola chiave?


È stato sottolineato che questa domanda potrebbe essere troppo ampia a causa di tutte queste domande nei dettagli della mia domanda. Volevo solo chiarire che queste domande sono solo per chiarire la confusione riguardo alla domanda principale.

Quando e per quali scopi la parola chiave const dovrebbe essere usata in C per le variabili?

Può anche essere riformulato come

L'uso corretto della constparola chiave in C` con i pro e i contro della stessa.


Per coloro che lo votano per essere chiuso, spiega perché non rientra nella categoria di Specific issues with software development. Sono abbastanza specifico.
Aseem Bansal,

Immagino sia perché hai posto più domande nello stesso post, e quindi la tua domanda rientra nella categoria di Too Broad: "Ci sono troppe risposte possibili o buone risposte sarebbero troppo lunghe per questo formato. Aggiungi dettagli restringere il set di risposte o isolare un problema a cui è possibile rispondere in pochi paragrafi. "
Robert Harvey,

1
@RobertHarvey Tutte queste domande sono solo per spiegare la mia confusione. La mia unica domanda rimane il titolo di questa domanda. Una buona risposta a ciò coprirebbe tutte queste domande correlate. Quindi rimane a specific issue. L'uso corretto della constparola chiave in C` con i pro e i contro della stessa.
Aseem Bansal,

@RobertHarvey È meglio adesso?
Aseem Bansal,

Risposte:


65

Durante la revisione del codice, applico le seguenti regole:

  • Utilizzare sempre constper i parametri della funzione passati per riferimento in cui la funzione non modifica (o libera) i dati indicati.

    int find(const int *data, size_t size, int value);
  • Usare sempre constper costanti che potrebbero altrimenti essere definite usando un #define o un enum. Di conseguenza, il compilatore può individuare i dati nella memoria di sola lettura (ROM) (sebbene il linker sia spesso uno strumento migliore a tale scopo nei sistemi integrati).

    const double PI = 3.14;
  • Non usare mai const in un prototipo di funzione per un parametro passato per valore . Non ha significato ed è quindi solo "rumore".

    // don't add const to 'value' or 'size'
    int find(const int *data, size_t size, const int value); 
    
  • Se del caso, utilizzare const volatilesu posizioni che non possono essere modificate dal programma ma che potrebbero comunque cambiare. I registri hardware sono il tipico caso d'uso qui, ad esempio un registro di stato che riflette uno stato del dispositivo:

    const volatile int32_t *DEVICE_STATUS =  (int32_t*) 0x100;

Altri usi sono opzionali. Ad esempio, i parametri a una funzione all'interno della funzione attuazione possono essere contrassegnati come const.

// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)  
{
     ... etc

o la funzione restituisce valori o calcoli ottenuti e che quindi non cambiano mai:

char *repeat_str(const char *str, size_t n) 
{
    const size_t len = strlen(str);
    const size_t buf_size = 1 + (len * n);
    char *buf = malloc(buf_size);
    ...

Questi usi constindicano semplicemente che non cambierai la variabile; non cambiano come o dove è memorizzata la variabile. Il compilatore può ovviamente capire che una variabile non è cambiata, ma aggiungendoti gli constconsenti di imporla. Questo può aiutare il lettore e aggiungere un po 'di sicurezza (anche se se le tue funzioni sono abbastanza grandi o abbastanza complicate da fare una grande differenza, probabilmente hai altri problemi). Modifica - ad es. una funzione densamente codificata di 200 righe con loop nidificati e molti nomi di variabili lunghi o simili, sapendo che alcune variabili non cambiano mai potrebbero facilitare la comprensione in modo significativo. Tali funzioni sono state progettate o mantenute male.


Problemi con const. Probabilmente sentirai il termine "avvelenamento const". Ciò si verifica quando l'aggiunta consta un parametro di funzione provoca la propagazione di "costanza".

Modifica - avvelenamento const: ad esempio nella funzione:

int function_a(char * str, int n)
{
    ...
    function_b(str);
    ...
}

se cambiamo strin const, dobbiamo quindi assicurarci che fuction_banche a const. E così via se function_bpassa stra function_c, ecc. Come puoi immaginare, potrebbe essere doloroso se si propaga in molti file / moduli separati. Se si propaga in una funzione che non può essere modificata (ad esempio una libreria di sistema), diventa necessario un cast. Quindi cospargere constnel codice esistente forse chiede problemi. Nel nuovo codice, tuttavia, è meglio constqualificarsi in modo coerente laddove appropriato.

Il problema più insidioso constè che non era nella lingua originale. Come componente aggiuntivo non si adatta perfettamente. Per cominciare ha due significati (come nelle regole sopra, che significa "non ho intenzione di cambiare questo" e "questo non può essere modificato"). Ma soprattutto, può essere pericoloso. Ad esempio, compila ed esegui questo codice e (a seconda del compilatore / delle opzioni) potrebbe bloccarsi quando eseguito:

const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';

strchrrestituisce un char*non a const char*. Poiché il suo parametro call è const, deve trasmettere il parametro call a char*. E in questo caso ciò elimina la vera proprietà di archiviazione di sola lettura. Modifica: - questo si applica generalmente ai var nella memoria di sola lettura. Per "ROM" intendo non solo la ROM fisica, ma qualsiasi memoria protetta da scrittura, come accade per la sezione di codice dei programmi eseguiti su un sistema operativo tipico.

Molte funzioni di libreria standard si comportano allo stesso modo, quindi attenzione: quando si hanno costanti reali (cioè memorizzate nella ROM) è necessario fare molta attenzione a non perdere la loro costanza.


Non ha davvero due significati. Significa solo, come dici tu, " non ho intenzione di cambiare questo". Ad esempio, è perfettamente valido avere una const volatilevariabile.
detly

2
Questo è vero per i parametri della funzione, ma per le costanti nell'ambito del file, ad esempio, una constvariabile è davvero di sola lettura: constdice "Questo non può essere modificato". A const volatiled'altra parte dice "Questo non può essere modificato, ma potrebbe cambiare". Aggiungerò una menzione di volatili alla mia risposta.
William Morris,

Non sono in disaccordo con il tuo commento, solo con l'idea che sia un'istruzione per il compilatore metterlo nella ROM. Ciò implica una sorta di guardia di runtime contro comportamenti indefiniti (ovvero la modifica di una const in qualche modo), che può portare a incomprensioni come "perché posso cambiare questa constvariabile attraverso un non constpuntatore" (una domanda comune su SO e su ogni altro forum C !). Nel complesso, comunque, mi piace questa risposta :)
detly

Hai ragione, "Metti questo in ROM" non è preciso (anche se conciso :-) - Lo cambierò in "Questo non può essere modificato", che è più preciso. Grazie per i tuoi commenti
William Morris,

Questa è un'ottima panoramica. Mi piace esprimerlo perconst dichiarare sia i dati di sola lettura sia le visualizzazioni di sola lettura dei dati, con la differenza che "non è possibile modificarlo" rispetto a "non è possibile modificarlo".
Jon Purdy,

8

Generalmente in qualsiasi linguaggio di programmazione si consiglia di utilizzare consto il modificatore equivalente da allora

  • Può chiarire al chiamante che ciò che è passato non cambierà
  • Potenziali miglioramenti della velocità poiché il compilatore sa per certo che può omettere alcune cose che sono rilevanti solo se il parametro può cambiare
  • Protezione da te stesso che modifica accidentalmente il valore

1

Sì, è sostanzialmente la risposta di TheLQ.

È una misura di sicurezza per il programmatore, quindi non modificare una variabile e non chiamare funzioni che potrebbero modificarle. In un array o una struttura lo identificatore const indica che i valori del loro contenuto non verranno modificati e nemmeno il compilatore non ti permetterà di farlo. Puoi comunque facilmente cambiare il valore della variabile con solo un cast.

In quello che ho visto di solito, viene principalmente utilizzato per aggiungere valori costanti nel codice e per indicare che l'array o la struttura non verranno modificati se si chiama una funzione particolare. Quest'ultima parte è importante, perché quando si chiama una funzione che modificherà l'array o la struttura, è possibile che si desideri conservare la versione originale, quindi si crea una copia della variabile e la si passa alla funzione. In caso contrario, ovviamente non è necessaria la copia, quindi ad esempio è possibile modificare,

int foo(Structure s);

per

int foo(const Structure * s);

e non ottenere l'overhead della copia.

Solo per aggiungere, nota che C ha regole particolari con l'identificatore const. Per esempio,

int b = 1;
const int * a = &b;

non è lo stesso di

int b = 1;
int * const a = &b;

Il primo codice non ti permetterà di modificare a. Nel secondo caso, il puntatore è costante ma il suo contenuto non lo è, quindi il compilatore ti permetterà di dire * a = 3;senza un errore del compilatore, ma non puoi farti ariferimento a un'altra cosa.


0

In accordo con le dichiarazioni di TheLQ:

Quando si lavora con un team di programmatori dichiarare constè un buon modo per indicare che detta variabile non dovrebbe essere modificata, o semplicemente per ricordare a te stesso in progetti di grandi dimensioni. È utile in questo senso e può salvare molti mal di testa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.