Statico, definitivo e const in C

Ho letto che le variabili statiche vengono utilizzate all’interno della funzione quando non si desidera che il valore della variabile venga modificato / inizializzato ogni volta che viene chiamata la funzione. Ma che dire della definizione di una variabile statica nel programma principale prima di “main” ad es

#include  static double m = 30000; int main(void) { value = m * 2 + 3; } 

Qui la variabile m ha un valore costante che non verrà modificato più avanti nel programma principale. Nella stessa linea di pensiero che differenza fa avere questi invece di usare la definizione statica:

 const double m = 30000; 

o

 #define m 30000 //m or M 

e quindi assicurarsi di utilizzare qui le doppie operazioni nel codice principale in modo da convertire m nel tipo di dati corretto.

 static double m = 30000; double foo(double x, double y) { return x/m + y; } 

Questo non ti porta nulla. Una copia di m deve essere fatta per fare il calcolo. Inoltre se lo fai:

 double bar( double x, double y) { m += x + y; return m; } 

Quindi tutte le chiamate alla barra cambieranno m. Le variabili statiche al di fuori delle funzioni (o delle classi) sono in realtà delle variabili globali con ambito file. Gli altri file non possono ottenerli da extern

Le variabili statiche all’interno di una funzione sono ancora come variabili globali, ad eccezione del fatto che anche altre funzioni nello stesso file non possono vederle direttamente.

 const double m = 30000; 

Questo è meglio e in molti casi migliore. Se il compilatore vede questo const globale e quindi vede un riferimento a m, allora sa che piuttosto che generare codice per caricare il valore da dove è (che probabilmente richiede il caricamento di un indirizzo letterale in un registro prima) in un registro o in una posizione di stack per fare calcoli può semplicemente fare in modo che un registro sia 30000 o talvolta generare un’istruzione con 30000 codificata proprio lì.

Il lato negativo di questo è che il compilatore deve supporre che altri file souce vorranno leggere m e deve effettivamente archiviare una copia come variabile (ma una variabile costante) nel file object.

Non sono sicuro che sia standard ma a volte puoi fare extern const double m = 30000; e il compilatore userà 30000 per ottimizzare e supporre che un altro file abbia effettivamente una copia di m che verrà archiviata nell’eseguibile. Puoi anche fare static const double m = 30000; e il compilatore può supporre che nessun altro si aspetterà che una copia di m sia memorizzata nel codice object generato da questo file sorgente.

fare

 #define m 30000 

è più rischioso Non riceverai un avviso o un errore se in precedenza c’era un’altra m dichiarata come variabile, costante o funzione. Inoltre, per i macro del preprocessore come questo è facile fare confusione. Per esempio:

 #define BASE_ADDRESS 48 #define MY_OFFSET 9 #define MY_ADDRESS BASE_ADDRESS+MY_OFFSET ... return MY_ADDRESS*4; 

Sì, questo è un esempio stupido, ma come appare dopo che il preprocessore ha finito

 ... return 48+9*4; 

Che è

  return 48+(9*4); 

E non è quello che probabilmente volevi.

Un altro posto in cui le macro sono cattive è quando si hanno costanti grandi, come le stringhe. Le stringhe richiedono che siano indirizzabili da un puntatore e sono più difficili da ottimizzare rispetto agli interi e ai numeri letterali o costanti in virgola mobile. Potresti facilmente creare un programma molto grande se hai un sacco di cose come:

 #define JIM "Jim" #define JOHN "John" 

e poi ha usato JIM e JOHN su tutti i tuoi programmi perché il compilatore potrebbe non essere in grado di vedere che hai veramente bisogno solo delle stringhe “Jom” e “John” una volta nel programma.

Detto questo, non è raro vedere costanti dichiarate in questo modo, e spesso vengono fatte correttamente in questo modo da persone che sanno cosa stanno facendo.

static significa che la variabile avrà durata di archiviazione statica e visibilità locale. In questo caso, viene utilizzato per la parte “visibilità locale” di questo – cioè significa che m è visibile solo all’interno di questa unità di traduzione (essenzialmente questo file dopo che è stato elaborato).

Quando scrivi const double m=3000; stai dicendo al compilatore di creare un simbolo m nel file object a cui puoi accedere da altri file. Il compilatore può incorporare il valore di m nel file in cui è definito, ma il simbolo deve ancora essere assegnato ai fini della compilazione separata.

Quando scrivi #define m 3000 stai solo usando una comodità sintattica per scrivere la stessa costante in più punti nel file sorgente.

static per un object dichiarato al di fuori di una funzione rende semplicemente l’object locale all’unità di traduzione (cioè non è accessibile da altri file .c ). Non lo rende costante. Che è stato const è per. Sono ortogonali in modo da poter avere uno o l’altro o entrambi.

per esempio

 static const double m = 5; 

#define dichiara una macro che (in questo caso) può essere utilizzata come valore costante. Non c’è alcun object, quindi const non si applica in quanto non c’è alcun object da modificare. Di conseguenza, non puoi prendere l’indirizzo di una macro.

… cambia / inizializza ogni volta che viene chiamata la funzione

Usi le parole “cambia” e “inizializza” come se fossero uguali, ma non lo sono

 void f(void) { static int a = 0; a++; // changed! printf("%d\n", a); } int main(void) { f(); f(); } /* # 1 # 2 */ 

Quando in ambito file (funzioni esterne) static non significa “const” come in “valore statico”, ma significa che l’identificatore può essere riferito solo in quell’unità di traduzione.

Quindi il tuo primo m senza const può ancora essere cambiato. Solo guardie const contro i cambiamenti. Ma se si omette la static se si collega in una libreria o in un altro file object che ha lo stesso identificatore non statico al campo di applicazione si otterranno dei conflitti in fase di collegamento.

#define è un’operazione di preprocessore e farà sì che tutte le occorrenze di m vengano sostituite da 30000 prima che avvenga la fase di compilazione. Gli altri due esempi sono variabili in buona fede. La variabile static esiste nell’unità di traduzione in cui è dichiarata e può essere modificata . La variabile const è di sola lettura.

Se il valore di m deve rimanere uguale per sempre, allora ovviamente puoi usarlo

 static const double m = 30000; 

o

 #define m 30000 

Basta notare che in C const oggetti hanno il collegamento esterno per impostazione predefinita, quindi per ottenere la dichiarazione const equivalente devi usare static const , non solo const .

Si noti inoltre che in linguaggio C gli oggetti const non sono costanti , ma piuttosto “variabili costanti”. Se hai bisogno di una costante vera (cioè un’ quadro che forma espressioni costanti ), devi usare #define o costante enum.

Quest’ultimo è normalmente un problema solo con costanti integrali. Nel tuo caso di un double l’approccio con [static] const potrebbe funzionare meglio.

Nell’ambito dello toplevel scope static significa che la variabile (o funzione) non può essere letta al di fuori di questo file sorgente – non sarà resa disponibile al linker e non causerà alcun conflitto di nomi quando collegato. Non ha alcun effetto sul fatto una variabile è costante o no – in effetti, tali variabili sono spesso specificatamente non-costanti in modo che l’inizializzazione possa essere memorizzata nella cache.

La differenza tra l’uso di const e #define è che il primo permette al compilatore di controllare il tuo uso di una costante.

La differenza principale è che con #define si esce dal sistema dei tipi. Il preprocessore non ha alcuna nozione di sicurezza di tipo, ambito ecc. Quindi ad esempio se in seguito si tenta di scrivere un ciclo come

for (int m = 0; m

hai una brutta sorpresa …

Inoltre, se usi #defines, vedrai il valore di 30000 solo quando esegui il debug del tuo codice, non il nome m . Ciò non sembra fare una grande differenza in questo caso, ma quando si usano nomi costanti e variabili significativi, lo fa davvero.