Ho visto la parola static
usata in diversi punti nel codice C; è come una funzione / classe statica in C # (dove l'implementazione è condivisa tra gli oggetti)?
Ho visto la parola static
usata in diversi punti nel codice C; è come una funzione / classe statica in C # (dove l'implementazione è condivisa tra gli oggetti)?
Risposte:
(1) è l'argomento più straniero se sei un principiante, quindi ecco un esempio:
#include <stdio.h>
void foo()
{
int a = 10;
static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d\n", a, sa);
}
int main()
{
int i;
for (i = 0; i < 10; ++i)
foo();
}
Questo stampa:
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60
Ciò è utile nei casi in cui una funzione deve mantenere uno stato tra le chiamate e non si desidera utilizzare le variabili globali. Attenzione, tuttavia, questa funzione dovrebbe essere usata con parsimonia - rende il tuo codice non sicuro per i thread e difficile da capire.
(2) È ampiamente utilizzato come funzionalità di "controllo degli accessi". Se si dispone di un file .c che implementa alcune funzionalità, in genere espone agli utenti solo alcune funzioni "pubbliche". Il resto delle sue funzioni dovrebbe essere fattostatic
, in modo che l'utente non sia in grado di accedervi. Questa è incapsulamento, una buona pratica.
Citando Wikipedia :
Nel linguaggio di programmazione C, statico viene utilizzato con variabili e funzioni globali per impostare il loro ambito sul file contenente. Nelle variabili locali, statico viene utilizzato per archiviare la variabile nella memoria allocata staticamente anziché nella memoria allocata automaticamente. Sebbene il linguaggio non imponga l'implementazione di nessuno dei due tipi di memoria, la memoria allocata staticamente è in genere riservata nel segmento di dati del programma al momento della compilazione, mentre la memoria allocata automaticamente viene normalmente implementata come stack di chiamate transitorio.
E per rispondere alla tua seconda domanda, non è come in C #.
In C ++, tuttavia, static
viene utilizzato anche per definire attributi di classe (condivisi tra tutti gli oggetti della stessa classe) e metodi. In C non ci sono classi, quindi questa funzione è irrilevante.
.c
o più file di intestazione, ma il diavolo è sempre in ciò che non è tipico.
C'è un altro uso non trattato qui, che è parte di una dichiarazione di tipo array come argomento di una funzione:
int someFunction(char arg[static 10])
{
...
}
In questo contesto, ciò specifica che gli argomenti passati a questa funzione devono essere una matrice di tipo char
con almeno 10 elementi al suo interno. Per maggiori informazioni vedi la mia domanda qui .
arg[0]
fino alla arg[9]
avere valori (che implica anche che la funzione non accetta un puntatore nullo). I compilatori potrebbero utilizzare queste informazioni in qualche modo per l'ottimizzazione e gli analizzatori statici possono utilizzare queste informazioni per garantire che alla funzione non venga mai assegnato un puntatore nullo (o, se è possibile, un array con meno elementi di quanto specificato).
static
in C99. È più di un decennio e mezzo, ma non tutti gli autori di compilatori hanno abbracciato tutte le funzionalità di C99, quindi il C99 nel suo insieme rimane in gran parte sconosciuto.
int arr[n];
, allora si tratta di un VLA (array di lunghezza variabile) , che è stato aggiunto in C99. È quello che volevi dire?
Risposta breve ... dipende.
Le variabili locali definite statiche non perdono il loro valore tra le chiamate di funzione. In altre parole, sono variabili globali, ma nell'ambito della funzione locale in cui sono definite.
Le variabili globali statiche non sono visibili al di fuori del file C in cui sono definite.
Le funzioni statiche non sono visibili al di fuori del file C in cui sono definite.
private
in C, la tua analogia è buona: statica rende le cose "private" in un dato file. E i file in C sono spesso associati a classi in C ++.
Esempio di ambito variabile multi-file
Qui illustrerò come statico influenza l'ambito delle definizioni delle funzioni su più file.
AC
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */
/*int i;*/
/* OK: extern. Will use the one in main. */
extern int i;
/* OK: only visible to this file. */
static int si = 0;
void a() {
i++;
si++;
puts("a()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
main.c
#include <stdio.h>
int i = 0;
static int si = 0;
void a();
void m() {
i++;
si++;
puts("m()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
int main() {
m();
m();
a();
a();
return 0;
}
Compila ed esegui:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Produzione:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Interpretazione
si
, una per ogni filei
Come al solito, minore è l'ambito, meglio è, quindi static
puoi sempre dichiarare le variabili se puoi.
Nella programmazione C, i file vengono spesso utilizzati per rappresentare "classi" e le static
variabili rappresentano membri statici privati della classe.
Cosa dicono gli standard al riguardo
C99 N1256 draft 6.7.1 " Identificatori della classe di archiviazione" indica che si static
tratta di un " identificatore della classe di archiviazione".
6.2.2 / 3 "Collegamenti di identificatori" static
indica che internal linkage
:
Se la dichiarazione di un identificatore di ambito di file per un oggetto o una funzione contiene l'identificatore di classe di archiviazione statico, l'identificatore ha un collegamento interno.
e 6.2.2 / 2 dice che internal linkage
si comporta come nel nostro esempio:
Nell'insieme di unità di traduzione e librerie che costituisce un intero programma, ogni dichiarazione di un particolare identificatore con collegamento esterno indica lo stesso oggetto o funzione. All'interno di un'unità di traduzione, ogni dichiarazione di un identificatore con collegamento interno indica lo stesso oggetto o funzione.
dove "unità di traduzione è un file sorgente dopo la preelaborazione.
In che modo GCC lo implementa per ELF (Linux)?
Con la STB_LOCAL
rilegatura.
Se compiliamo:
int i = 0;
static int si = 0;
e disassemblare la tabella dei simboli con:
readelf -s main.o
l'output contiene:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
quindi l'associazione è l'unica differenza significativa tra di loro. Value
è solo il loro offset nella .bss
sezione, quindi ci aspettiamo che differisca.
STB_LOCAL
è documentato sulle specifiche ELF all'indirizzo http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL I simboli locali non sono visibili all'esterno del file oggetto che contiene la loro definizione. Simboli locali con lo stesso nome possono esistere in più file senza interferire tra loro
che lo rende una scelta perfetta da rappresentare static
.
Le variabili senza statico sono STB_GLOBAL
e la specifica dice:
Quando l'editor di collegamenti combina diversi file di oggetti trasferibili, non consente più definizioni di simboli STB_GLOBAL con lo stesso nome.
che è coerente con gli errori di collegamento su più definizioni non statiche.
Se ottimizziamo l'ottimizzazione con -O3
, il si
simbolo viene rimosso completamente dalla tabella dei simboli: non può comunque essere utilizzato dall'esterno. TODO perché mantenere le variabili statiche sulla tabella dei simboli quando non c'è ottimizzazione? Possono essere usati per qualsiasi cosa? Forse per il debug.
Guarda anche
static
funzioni: https://stackoverflow.com/a/30319812/895245static
con extern
, che fa "il contrario": Come posso usare extern per condividere variabili tra i file sorgente?Spazi dei nomi anonimi C ++
In C ++, potresti voler usare spazi dei nomi anonimi anziché statici, il che ottiene un effetto simile, ma nasconde ulteriormente le definizioni dei tipi: spazi dei nomi senza nome / anonimi rispetto alle funzioni statiche
Dipende:
int foo()
{
static int x;
return ++x;
}
La funzione restituirebbe 1, 2, 3, ecc. --- la variabile non è nello stack.
static int foo()
{
}
Significa che questa funzione ha ambito solo in questo file. Quindi ac e bc possono avere diversi foo()
s e foo non è esposto a oggetti condivisi. Quindi, se hai definito foo in ac, non puoi accedervi da b.c
o da qualsiasi altro luogo.
Nella maggior parte delle librerie C tutte le funzioni "private" sono statiche e la maggior parte "pubbliche" non lo sono.
La gente continua a dire che "statico" in C ha due significati. Offro un modo alternativo di vederlo che gli dà un unico significato:
La ragione per cui sembra avere due significati è che, in C, ogni elemento a cui 'statico' può essere applicato ha già una di queste due proprietà , quindi sembra che quel particolare uso coinvolga solo l'altro.
Ad esempio, considera le variabili. Le variabili dichiarate al di fuori delle funzioni hanno già persistenza (nel segmento di dati), quindi l'applicazione di 'statico' può renderle non visibili al di fuori dell'ambito corrente (unità di compilazione). Al contrario, le variabili dichiarate all'interno delle funzioni hanno già una non visibilità al di fuori dell'attuale ambito (funzione), quindi l'applicazione di "statico" può solo renderle persistenti.
Applicare 'statico' alle funzioni è proprio come applicarlo a variabili globali - il codice è necessariamente persistente (almeno all'interno della lingua), quindi solo la visibilità può essere modificata.
NOTA: questi commenti si applicano solo a C. In C ++, l'applicazione di metodi "statici" ai metodi di classe sta davvero dando alla parola chiave un significato diverso. Allo stesso modo per l'estensione di argomento array C99.
static
fornisce un collegamento interno a un identificatore.
Da Wikipedia:
Nel linguaggio di programmazione C, statico viene utilizzato con variabili e funzioni globali per impostare il loro ambito sul file contenente. Nelle variabili locali, statico viene utilizzato per archiviare la variabile nella memoria allocata staticamente anziché nella memoria allocata automaticamente. Sebbene il linguaggio non imponga l'implementazione di nessuno dei due tipi di memoria, la memoria allocata staticamente è in genere riservata nel segmento di dati del programma al momento della compilazione, mentre la memoria allocata automaticamente viene normalmente implementata come stack di chiamate transitorio.
static
significa cose diverse in contesti diversi.
È possibile dichiarare una variabile statica in una funzione C. Questa variabile è visibile solo nella funzione, tuttavia si comporta come un globale in quanto viene inizializzata una sola volta e mantiene il suo valore. In questo esempio, ogni volta che lo chiami foo()
, verrà stampato un numero crescente. La variabile statica viene inizializzata una sola volta.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
Un altro uso di static è quando si implementa una funzione o una variabile globale in un file .c ma non si desidera che il suo simbolo sia visibile al di fuori di quello .obj
generato dal file. per esempio
static void foo() { ... }
Se si dichiara una variabile in una funzione statica, il suo valore non verrà memorizzato nello stack di chiamate di funzione e sarà comunque disponibile quando si chiama di nuovo la funzione.
Se dichiari una variabile globale statica, il suo ambito sarà limitato all'interno del file in cui l'hai dichiarata. Questo è leggermente più sicuro di un normale globale che può essere letto e modificato durante l'intero programma.
Odio rispondere a una vecchia domanda, ma non credo che nessuno abbia menzionato il modo in cui K&R lo spiega nella sezione A4.1 di "Il linguaggio di programmazione C".
In breve, la parola statica viene utilizzata con due significati:
static
parola chiave (grande enfasi sul fatto che viene utilizzata nel codice come parola chiave) viene utilizzata con una dichiarazione, fornisce tale collegamento interno all'oggetto in modo che possa essere utilizzata solo all'interno di tale unità di traduzione. Ma se la parola chiave viene utilizzata in una funzione, cambia la classe di archiviazione dell'oggetto (l'oggetto sarebbe comunque visibile solo all'interno di quella funzione). L'opposto di static è la extern
parola chiave, che fornisce un oggetto collegamento esterno.Peter Van Der Linden dà questi due significati in "Programmazione Expert C":
register
un identificatore della classe di archiviazione (C99 6.7.1 Identificatori della classe di archiviazione). Ed è molto più di un semplice suggerimento, ad esempio non è possibile applicare l'indirizzo dell'operatore &
su un oggetto con classe di archiviazione register
indipendentemente dal fatto che il compilatore alloca un registro o meno.
In C, statico ha due significati, a seconda dell'ambito del suo utilizzo. Nell'ambito globale, quando un oggetto viene dichiarato a livello di file, significa che l'oggetto è visibile solo all'interno di quel file.
In qualsiasi altro ambito dichiara un oggetto che manterrà il suo valore tra le diverse volte in cui viene inserito lo specifico ambito. Ad esempio, se un int viene eliminato all'interno di una procedura:
void procedure(void)
{
static int i = 0;
i++;
}
il valore di 'i' viene inizializzato su zero alla prima chiamata alla procedura e il valore viene mantenuto ogni volta che viene chiamata la procedura. se 'i' venisse stampato emetterebbe una sequenza di 0, 1, 2, 3, ...
È importante notare che le variabili statiche nelle funzioni vengono inizializzate alla prima voce in quella funzione e persistono anche dopo che la loro chiamata è terminata; in caso di funzioni ricorsive la variabile statica viene inizializzata una sola volta e persiste anche su tutte le chiamate ricorsive e anche dopo che la chiamata della funzione è terminata.
Se la variabile è stata creata al di fuori di una funzione, significa che il programmatore è in grado di utilizzare la variabile solo nel file sorgente in cui è stata dichiarata la variabile.
Se lo dichiari in un mytest.c
file:
static int my_variable;
Quindi questa variabile può essere vista solo da questo file. La variabile non può essere esportata altrove.
Se si dichiara all'interno di una funzione, il valore della variabile manterrà il suo valore ogni volta che viene chiamata la funzione.
Una funzione statica non può essere esportata dall'esterno del file. Quindi, in un *.c
file, nascondi le funzioni e le variabili se le dichiari statiche.
Le variabili statiche in C hanno la durata del programma.
Se definiti in una funzione, hanno un ambito locale, cioè sono accessibili solo all'interno di tali funzioni. Il valore delle variabili statiche viene conservato tra le chiamate di funzione.
Per esempio:
void function()
{
static int var = 1;
var++;
printf("%d", var);
}
int main()
{
function(); // Call 1
function(); // Call 2
}
Nel programma sopra, var
è memorizzato nel segmento di dati. La sua durata è l'intero programma C.
Dopo la chiamata di funzione 1, var
diventa 2. Dopo la chiamata di funzione 2, var
diventa 3.
Il valore di var
non viene distrutto tra le chiamate di funzioni.
Se var
avesse una variabile non statica e locale, verrebbe memorizzata nel segmento dello stack nel programma C. Poiché il frame dello stack della funzione viene distrutto dopo il ritorno della funzione, var
viene distrutto anche il valore di .
Le variabili statiche inizializzate sono memorizzate nel segmento di dati del programma C, mentre quelle non inizializzate sono memorizzate nel segmento BSS.
Un'altra informazione su statica: se una variabile è globale e statica, ha la durata del programma C, ma ha un ambito di file. È visibile solo in quel file.
Per provare questo:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
extern int x;
func()
{
printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
}
run gcc -c file1.c
gcc -c file2.c
Ora prova a collegarli usando:
gcc -o output file1.o file2.o
Darebbe un errore del linker poiché x ha l'ambito del file file1.c e il linker non sarebbe in grado di risolvere il riferimento alla variabile x utilizzata in file2.c.
Riferimenti:
static int var = 1;
cambia il valore in uno ogni volta
Una variabile statica è una variabile speciale che è possibile utilizzare in una funzione e salva i dati tra le chiamate e non le elimina tra le chiamate. Per esempio:
void func(){
static int count; // If you don't declare its value, the value automatically initializes to zero
printf("%d, ", count);
++count;
}
void main(){
while(true){
func();
}
}
Il risultato:
0, 1, 2, 3, 4, 5, ...
printf("%d, ", count); count++;
con `printf ("% d, ", count ++) (non importa: P).
Ci sono 2 casi:
(1) Variabili locali dichiarate static
: allocate nel segmento di dati anziché nello stack. Il suo valore viene mantenuto quando si chiama di nuovo la funzione.
(2) Variabili o funzioni globali dichiarate static
: unità di compilazione esterna invisibile (ovvero sono simboli locali nella tabella dei simboli durante il collegamento).
Le variabili statiche hanno la proprietà di preservare il loro valore anche dopo che sono fuori dal loro ambito! Pertanto, le variabili statiche conservano il loro valore precedente nel loro ambito precedente e non vengono nuovamente inizializzate nel nuovo ambito.
Guarda questo per esempio: una variabile int statica rimane in memoria mentre il programma è in esecuzione. Una variabile normale o automatica viene distrutta quando termina una chiamata di funzione in cui è stata dichiarata la variabile.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Questo produrrà: 1 2
Poiché 1 rimane in memoria poiché è stato dichiarato statico
Le variabili statiche (come le variabili globali) vengono inizializzate come 0 se non inizializzate esplicitamente. Ad esempio nel seguente programma, il valore di x viene stampato come 0, mentre il valore di y è qualcosa di immondizia. Vedi questo per maggiori dettagli.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Questo produrrà: 0 [some_garbage_value]
Questi sono i principali che ho scoperto che non sono stati spiegati sopra per un principiante!
Nella programmazione C, static
è una parola chiave riservata che controlla sia la durata che la visibilità. Se dichiariamo una variabile come statica all'interno di una funzione, sarà visibile solo attraverso quella funzione. In questo utilizzo, la durata di questa variabile statica inizierà quando una funzione chiama e si distruggerà dopo l'esecuzione di quella funzione. puoi vedere il seguente esempio:
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
Il programma sopra ci darà questo risultato:
First Counter Output = 1
Second Counter Output = 1
Perché non appena chiamiamo la funzione, verrà inizializzato count = 0
. E mentre eseguiamo il counterFunction
, distruggerà la variabile count.