2010-04-09 12 views
16

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.Statico, definitivo e const in C

#include <stdio.h> 

static double m = 30000; 

int main(void) 
{ 
value = m * 2 + 3; 
} 

Qui la variabile m ha un valore costante che non verrà modificato in seguito nel programma principale. Nella stessa linea di pensiero quello differenza fa avere questi invece di utilizzare la definizione statica:

const double m = 30000; 

o

#define m 30000 //m or M 

e quindi fare in modo qui di utilizzare doppi operazioni nel codice principale così come convertire m nel tipo di dati corretto.

+0

Grazie a tutti per le risposte interessanti. Quindi penso che la cosa migliore nel mio caso sia avere const stat double = 30000. – yCalleecharan

risposta

12
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. Anche se si fa:

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

Poi tutte le chiamate al bar cambierà m. Le variabili statiche al di fuori delle funzioni (o delle classi) sono in realtà delle variabili globali con ambito file. Altri file non possono ottenerli dall'esterno

Le variabili statiche all'interno di una funzione sono ancora come variabili globali, tranne che anche altre funzioni nello stesso file non possono vederle direttamente.

const double m = 30000; 

Questo è migliore 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 presupporre che altri file souce vorranno leggere m e deve effettivamente archiviare una copia come variabile (ma una variabile costante) nel file oggetto.

Non sono sicuro che sia standard ma a volte è possibile eseguire extern const double m = 30000; e il compilatore utilizzerà 30000 per ottimizzare e presupporre 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 oggetto generato da questo file sorgente.

Facendo

#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 che cosa questo sembra dopo che il preprocessore viene fatto con esso è

... 
    return 48+9*4; 

Qual è

return 48+(9*4); 

E questo è non quello che probabilmente volevi.

Un altro punto in cui le macro sono errate è 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. Si potrebbe facilmente fare un grande programma se tu avessi un sacco di roba del genere:

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

e poi utilizzato JIM e John in tutto i programmi perché il compilatore potrebbe non essere in grado di vedere che si ha realmente bisogno solo le stringhe " Jom "e" John "una volta nel programma.

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

+0

Grazie per la lunga spiegazione. Quindi se ho tutti i codici in un singolo file, allora const statico double m = 30000 è la risposta migliore che presumo. – yCalleecharan

+0

Tutti i compilatori riconosceranno due stringhe letterali identiche e le memorizzeranno una sola volta. – Tomas

+0

In alcuni casi si ha a che fare con 'define' invece di' const'. 'static const uint8_t ARRAY_SIZE = 16U; uint8_t array [ARRAY_SIZE] 'non funziona perché 'ARRAY_SIZE' non è un valore costante esplicito. Lo stesso con 'const uint8_t SECONDS_PER_MINUTE = 60U; const uint16_t SECONDS_PER_HOUR = 60U * SECONDS_PER_MINUTE; ', non funziona. È una grande vergogna. – Gauthier

5

static per un oggetto dichiarato all'esterno di una funzione si limita a rendere l'oggetto locale all'unità di traduzione (ovvero non è accessibile da altri file .c). Non lo rende costante. Che era const è per. Sono ortogonali in modo da poter avere uno o l'altro o entrambi.

ad es.

static const double m = 5; 

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

+0

Solo per aggiungere un po ': 'const' e' static' non sono tanto ortogonali in C++ quanto in C. In C++, una variabile 'const' definita all'esterno di una funzione è anche' static' di default. –

+0

@Jerry: Certo, ma questa è una domanda C e una domanda per principianti, quindi è probabilmente un dettaglio che non vale la pena di complicare la risposta. –

+0

La parola giusta è ortogonale? O intendevi mutuo? come hai detto possiamo o l'uno o l'altro o entrambi. – yCalleecharan

7

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

1

Nell'ambito toplevel static significa che la variabile (o funzione) non è accessibile al di fuori di questo file di origine - non verrà resa disponibile al linker e non causerà alcun conflitto di nomi quando collegato. nessun effetto sul fatto che una variabile sia costante o meno - in effetti, tali variabili sono spesso specificatamente non-costanti, così che l'inizializzazione può essere memorizzata nella cache.

La differenza tra l'utilizzo di const e #define è che il primo permette al compilatore di tipo-controllare l'utilizzo di una costante.

1

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

for (int m = 0; m < dimensioni; m ++) {...}

si sono fino a una brutta sorpresa ...

anche se usi #defines, vedrai il valore di 30000 solo durante 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.

+0

Grazie. È interessante conoscere questo suggerimento per il debug. – yCalleecharan

2

...cambiamento/inizializzare ogni volta che la funzione viene chiamata

Si utilizza le parole "cambiamento" e "inizializzare" come se fossero la stessa cosa, ma non sono

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

int main(void) { 
    f(); f(); 
} 

/* 
    # 1 
    # 2 
*/ 

Quando alla lima-scope (funzioni esterne) static non significa "const" come in "valore statico", ma significa che l'identificatore può essere riferito solo a quell'unità di traduzione.

Quindi il tuo primo m senza const può ancora essere modificato. Solo const guardie contro le modifiche. Ma se si omette static, se si collega in una libreria o in un altro file oggetto che ha lo stesso identificatore non statico in ambito di file, si otterranno conflitti in fase di collegamento.

2

#define è un'operazione preprocessore e causerà tutte le occorrenze di m essere sostituiti da 30000 prima della fase di compilazione avviene. 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.

5

Quando si scrive const double m=3000; si sta dicendo al compilatore di creare un simbolo m nel file oggetto a cui è possibile accedere da altri file. Il compilatore può incorporare il valore di m nel file in cui è definito, ma il simbolo è ancora da assegnare ai fini della compilazione separata.

Quando si scrive #define m 3000 si utilizza solo una comodità sintattica per scrivere la stessa costante in più punti nel file di origine.

2

Se il valore della m deve rimanere lo stesso per sempre, poi, naturalmente, è possibile utilizzare

static const double m = 30000; 

o

#define m 30000 

Basta notare che in C const oggetti hanno collegamento esterno di default , quindi per ottenere la dichiarazione equivalente const è necessario utilizzare static const, non solo const.

Si noti inoltre che in linguaggio C const gli oggetti non sono costanti, ma piuttosto "variabili costanti". Se hai bisogno di una costante (ovvero un'entità che forma le espressioni costanti )), devi utilizzare la costante #define o enum.

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