So cosa significa quando la funzione statica è dichiarata nel file sorgente. Sto leggendo del codice, ho scoperto che la funzione statica nei file di intestazione potrebbe essere richiamata in altri file.C/C++: funzione statica nel file di intestazione, cosa significa?
risposta
La funzione è definita nel file di intestazione? In modo che il codice vero e proprio è dato direttamente nella funzione, in questo modo:
static int addTwo(int x)
{
return x + 2;
}
Allora questo è solo un modo di fornire una funzione utile per molti file C differenti. Ogni file C che include l'intestazione avrà la propria definizione che può chiamare. Questo ovviamente spreca memoria, ed è (secondo me) una cosa abbastanza brutta da fare, dato che avere un codice eseguibile in un header non è generalmente una buona idea.
Ricorda che #include
: l'intestazione in pratica incolla semplicemente il contenuto dell'intestazione (e di eventuali altre intestazioni incluse da esso) nel file C come visualizzato dal compilatore. Il compilatore non sa mai che una particolare definizione di funzione proviene da un file di intestazione.
UPDATE: In molti casi, in realtà è una buona idea per fare qualcosa di simile al precedente, e mi rendo conto la mia risposta suona molto in bianco e nero di questo tipo che è di semplificare eccessivamente le cose un po '. Per esempio, il codice che i modelli (o utilizza solo) intrinsic functions può essere espresso come il precedente, e con un esplicito inline
parola chiave anche:
static inline int addTwo(int *x)
{
__add_two_superquickly(x);
}
Qui, la funzione __add_two_superquickly()
è un intrinseco immaginario, e dato che vogliamo l'intero funzione per compilare fondamentalmente fino a una singola istruzione, vogliamo davvero che sia in linea. Tuttavia, quanto sopra è più pulito rispetto all'utilizzo di una macro.
Il vantaggio rispetto all'uso diretto intrinseco è naturalmente che avvolgendolo in un altro livello di astrazione rende possibile creare il codice su compilatori privi di quel particolare intrinseco, fornendo un'implementazione alternativa e scegliendo quella giusta in base alla quale il compilatore è in uso.
In pratica creerà una funzione statica separata con lo stesso nome all'interno di ogni file cpp in cui è incluso. Lo stesso vale per le variabili globali.
Come altri stanno dicendo, ha esattamente lo stesso significato della funzione static
nel file .c
stesso. Questo perché non esiste una differenza semantica tra i file .c
e .h
; c'è solo l'unità di compilazione composta dal file effettivamente passato al compilatore (di solito chiamato .c
) con i contenuti di tutti i file denominati in #include
righe (di solito denominate) inserite nello stream come vengono viste dal preprocessore.
La convenzione che la sorgente C si trova in un file denominato .c
e le dichiarazioni pubbliche si trovano nei file denominati .h
è solo una convenzione. Ma è generalmente buono. In base a tale convenzione, le sole cose che dovrebbero apparire nei file .h
sono dichiarazioni in modo da evitare generalmente che lo stesso simbolo sia definito più volte in un singolo programma.
In questo caso particolare, la parola chiave static
rende il simbolo privato del modulo, quindi non esiste un conflitto a più definizioni in attesa di causare problemi. Quindi in questo senso, è sicuro di fare.Ma in assenza di una garanzia che la funzione sarebbe stata sottolineata, si corre il rischio che la funzione venga istanziata in ogni modulo che è successo a #include
quel file di intestazione che nel migliore dei casi è uno spreco di memoria nel segmento di codice.
Non sono sicuro di quali casi d'uso giustificassero di fare questo in un colpo di testa pubblico generalmente disponibile.
Se il file viene generato .h
codice e incluso solo in un unico file .c
, quindi vorrei personalmente il nome del file qualcosa di diverso .h
sottolineare che non è in realtà un colpo di testa del pubblico a tutti. Ad esempio, un'utilità che converte un file binario in una definizione di variabile inizializzata potrebbe scrivere un file che è destinato ad essere utilizzato tramite #include
e potrebbe benissimo contenere una dichiarazione static
della variabile ed eventualmente anche le definizioni static
di accessor o altra utilità correlata funzioni.
Forse la funzione contiene variabili statiche che preservano il loro valore tra le chiamate (stato interno), e quindi ogni modulo ottiene "la propria copia privata" dei vars avendo il proprio clone della funzione? –
@ranReloaded, Questa è una possibilità. Lo evitavo personalmente perché avrebbe fornito troppe possibilità a un intelligente ottimizzatore (o al manutentore del codice) di romperlo eliminando "intelligentemente" i corpi funzione apparentemente ridondanti. Inoltre, fornisce esattamente un insieme di stati interni per unità di traduzione. Sarebbe meno confuso e meno fragile mettere tutto lo stato in una variabile di stato esplicita, inoltrata a ogni chiamata. – RBerteig
Sì, non sono d'accordo nemmeno con questo "design". Vorrei piuttosto incapsulare dati privati in file vars statici globali (C) o membri di classe (C++) –
Non c'è differenza semantica nella definizione nel file di origine o nel file di intestazione, in pratica entrambi significano lo stesso in C normale quando si utilizza la parola chiave statica che, si limita l'ambito.
Tuttavia, c'è un problema nella scrittura di questo nel file di intestazione, questo perché ogni volta che includi l'intestazione in un file sorgente avrai una copia della funzione con la stessa implementazione che è molto simile ad avere un normale funzione definita nel file di intestazione. Aggiungendo la definizione nell'intestazione non si ottiene ciò che si intende per funzione statica.
Pertanto, suggerisco di avere l'implementazione solo nel file sorgente e non nell'intestazione.
C'è una forte differenza semantica se la funzione contiene una variabile locale statica. In un caso, la variabile statica sarà condivisa, nell'altro caso ci saranno più variabili statiche differenti per ogni unità di compilazione. Pertanto, il comportamento della funzione può essere completamente diverso. – galinette
È utile in alcune librerie "solo intestazioni" con funzioni inline di piccole dimensioni. In tal caso, si desidera sempre fare una copia della funzione, quindi non è un cattivo motivo. Tuttavia, questo ti dà un modo semplice per inserire interfaccia e implementazione parti separate nel singolo file di intestazione:
// header.h
// interface part (for user?!)
static inline float av(float a, float b);
// implementation part (for developer)
static inline float av(float a, float b)
{
return (a+b)/2.f;
}
di Apple biblioteca matematica vettoriale nel quadro GLK utilizza tale constuction (ad esempio GLKMatrix4.h).
Se si definisce la funzione in un file di intestazione (non semplicemente lo si dichiara), verrà generata una copia della funzione in ogni unità di traduzione (in pratica in ciascun file cpp che include questa intestazione).
Questo può aumentare la dimensione del file eseguibile, ma questo può essere trascurabile se la funzione è piccola. Il vantaggio è che la maggior parte dei compilatori può incorporare la funzione, il che può aumentare le prestazioni del codice.
Ma ci potrebbe essere una differenza grande nel fare ciò che non è stato menzionato in alcuna risposta. Se la funzione utilizza una variabile locale statica come ad esempio:
static int counter()
{
static int ctr = 0;
return ctr++;
}
Piuttosto che:
//header
int counter();
//source
int counter()
{
static int ctr = 0;
return ctr++;
}
Poi ogni file sorgente tra cui questa intestazione avrà un proprio contatore. Se la funzione è dichiarata nell'intestazione e definita in un file sorgente, il contatore verrà condiviso nell'intero programma.
Così dicendo che l'unica differenza saranno le prestazioni e la dimensione del codice è sbagliata.
- 1. Cosa significa "^ @" nel file?
- 2. cosa significa nuova statica?
- 3. Cosa significa "CC Graph Reduction" in Firefox Performance tool?
- 4. Cosa succede se implemento una classe nel file di intestazione?
- 5. cosa significa! Funzione in Javascript significa?
- 6. Che cosa significa jolly nel makefile?
- 7. Che cosa significa "CL" nel messaggio di commit? Cosa significa?
- 8. Cosa significa intestazione HTTP If-None-Match: * significa?
- 9. definisce la funzione statica all'esterno della classe e accede al valore statico .h e .cc file
- 10. Quando inserire la funzione C++ nel file di intestazione
- 11. Funzione inline nel file di intestazione in C
- 12. Cosa significa!() Nel costruttore di dati?
- 13. vuoto funzione Javascript? Cosa significa?
- 14. Cosa significa `* &` in una dichiarazione di funzione?
- 15. Nei makefile cosa significano CC e LD?
- 16. ItemsControl con intestazione statica
- 17. Cosa significa '2E4' nel codice
- 18. Incluso il file di intestazione dalla libreria statica
- 19. Cosa significa la funzione dir() di Python?
- 20. definizione multiple nel file di intestazione
- 21. Cosa significa frame_dummy nel contesto della profilazione?
- 22. const variabili nel file di intestazione e fiasco di inizializzazione statica
- 23. Che cosa significa "WINAPI" nella funzione principale?
- 24. Che cosa significa P :: ************ nel file Boost assert.hpp?
- 25. Che cosa significa la tilde (~) nel mio file composer.json?
- 26. Cosa significa "m" nel codice java
- 27. Come usare la funzione dalla libreria statica se non ho il file di intestazione
- 28. Cosa significa BootstrapperPackage nel progetto * .csproj
- 29. Cosa significa require ('../') significa?
- 30. Cosa significa '::' significa?
Bene, il compilatore probabilmente incorpora funzioni brevi. Quindi potrebbe effettivamente utilizzare meno memoria, se la funzione è abbastanza breve.Ma vorrei anteporre un "inline", quindi non si ottengono avvisi di compilazione sulle funzioni statiche non utilizzate. – quinmars
@quinmars Buon punto, ho modificato. Meglio tardi, spero. :) Grazie. – unwind
Mi chiedo se il linker lo ottimizzerà. Vede che addTwo su b.obj non viene referenziato, quindi rimuove la definizione dall'oggetto? In tal caso, l'overhead è solo la (dimensione della funzione) * (numero di diversi file obj che lo fanno riferimento). Ancora più grande di (dimensione della funzione), ma non così male? – doorfly