Risposte:
Quando si scrive un file di implementazione ( .cpp
, .cxx
, ecc) il compilatore genera un'unità di traduzione . Questo è il file sorgente dalla tua implementazione più tutte le intestazioni che ci hai #include
inserito.
Il collegamento interno si riferisce a tutto solo nell'ambito di un'unità di traduzione .
Il collegamento esterno si riferisce a cose che esistono al di là di una particolare unità di traduzione. In altre parole, accessibile attraverso l'intero programma , che è la combinazione di tutte le unità di traduzione (o file oggetto).
const
qui manca totalmente la domanda sulla regola delle variabili (così come sul suo scopo).
Come ha detto dudewat, il collegamento esterno significa che il simbolo (funzione o variabile globale) è accessibile in tutto il programma e il collegamento interno significa che è accessibile solo in un'unità di traduzione .
È possibile controllare esplicitamente il collegamento di un simbolo utilizzando le parole chiave extern
e static
. Se il collegamento non è specificato, il collegamento predefinito è extern
per i non const
simboli e static
(interno) per i const
simboli.
// in namespace or global scope
int i; // extern by default
const int ci; // static by default
extern const int eci; // explicitly extern
static int si; // explicitly static
// the same goes for functions (but there are no const functions)
int foo(); // extern by default
static int bar(); // explicitly static
Si noti che invece di utilizzare static
per il collegamento interno è meglio utilizzare spazi dei nomi anonimi in cui è anche possibile inserire class
es. Il collegamento per spazi dei nomi anonimi è cambiato tra C ++ 98 e C ++ 11, ma la cosa principale è che non sono raggiungibili da altre unità di traduzione.
namespace {
int i; // external linkage but unreachable from other translation units.
class invisible_to_others { };
}
extern
dichiarazione corrispondente nell'altro file.static
. Si dice che tali variabili abbiano un collegamento interno .Prendi in considerazione il seguente esempio:
void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
int a;
//...
f(a);
//...
f(a);
//...
}
f
dichiara f
come una funzione con collegamento esterno (impostazione predefinita). La sua definizione deve essere fornita più avanti in questo file o in un'altra unità di traduzione (fornita di seguito).max
è definito come una costante intera. Il collegamento predefinito per le costanti è interno . Il suo collegamento viene modificato in esterno con la parola chiave extern
. Quindi ora è max
possibile accedere in altri file.n
è definito come una variabile intera. Il collegamento predefinito per le variabili definite all'esterno dei corpi funzione è esterno .#include <iostream>
using namespace std;
extern const int max;
extern int n;
static float z = 0.0;
void f(int i)
{
static int nCall = 0;
int a;
//...
nCall++;
n++;
//...
a = max * z;
//...
cout << "f() called " << nCall << " times." << endl;
}
max
viene dichiarato di avere un collegamento esterno . Una definizione corrispondente per max
(con collegamento esterno) deve apparire in alcuni file. (Come in 1.cpp)n
viene dichiarato di avere un collegamento esterno .z
è definito come una variabile globale con collegamento interno .nCall
specifica nCall
di essere una variabile che mantiene il suo valore tra le chiamate per funzionare f()
. A differenza delle variabili locali con la classe di memorizzazione automatica predefinita, nCall
verranno inizializzati solo una volta all'inizio del programma e non una volta per ogni chiamata di f()
. L'identificatore della classe di archiviazione static
influisce sulla durata della variabile locale e non sul suo ambito.NB: la parola chiave ha static
un doppio ruolo. Se utilizzato nelle definizioni delle variabili globali, specifica il collegamento interno . Se utilizzato nelle definizioni delle variabili locali, specifica che la durata della variabile sarà la durata del programma anziché essere la durata della funzione.
Spero che aiuti!
static
consente l'inizializzazione singola pigra (che può essere utile se hai bisogno di un oggetto globale ish ma devi controllare quando è costruito a causa di problemi con l'ordine di costruzione globale e non puoi allocarlo dinamicamente usare new
mentre schemi di inizializzazione più approfonditi possono andare al di là di quanto è necessario per l'oggetto in questione; di conseguenza, questo è principalmente un problema per i sistemi embedded che usano C ++).
Parliamo di diversi scopi in 'C'
CAMPO DI APPLICAZIONE: Fondamentalmente è quanto posso vedere qualcosa e quanto lontano.
Variabile locale: Scope è solo all'interno di una funzione. Risiede nell'area STACK della RAM. Ciò significa che ogni volta che una funzione viene chiamata tutte le variabili che fanno parte di quella funzione, inclusi gli argomenti della funzione, vengono appena creati e vengono distrutti una volta che il controllo esce dalla funzione. (Perché lo stack viene scaricato ogni volta che la funzione ritorna)
Variabile statica: lo scopo di questo è per un file. È accessibile ovunque nel file
in cui è dichiarato. Risiede nel segmento DATA della RAM. Dal momento che questo è accessibile solo all'interno di un file e quindi collegamento INTERNO. Tutti gli
altri file non possono vedere questa variabile. In effetti la parola chiave STATIC è l'unico modo in cui possiamo introdurre un certo livello di dati o
nascondere la funzione in 'C'
Variabile globale: lo scopo di questo è per un'intera applicazione. È accessibile da ogni parte dell'applicazione. Le variabili globali risiedono anche nel segmento DATA poiché è possibile accedervi ovunque nell'applicazione e quindi nel collegamento ESTERNO
Per impostazione predefinita, tutte le funzioni sono globali. Nel caso, se è necessario nascondere alcune funzioni in un file dall'esterno, è possibile aggiungere come prefisso la parola chiave statica alla funzione. :-)
Prima di parlare della domanda, è meglio conoscere con precisione il termine unità di traduzione , programma e alcuni concetti di base del C ++ (in realtà il collegamento è uno di questi in generale). Dovrai anche sapere cos'è uno scopo .
Sottolineerò alcuni punti chiave, esp. quelli mancanti nelle risposte precedenti.
Il collegamento è una proprietà di un nome , che viene introdotto da una dichiarazione . Nomi diversi possono indicare la stessa entità (in genere un oggetto o una funzione). Pertanto, parlare del collegamento di un'entità è di solito senza senso, a meno che non si sia sicuri che l'entità verrà riferita solo con il nome univoco da alcune dichiarazioni specifiche (di solito una dichiarazione, però).
Nota un oggetto è un'entità, ma una variabile non lo è. Mentre si parla del collegamento di una variabile, in realtà il nome dell'entità indicata (che viene introdotto da una specifica dichiarazione) è interessato. Il collegamento del nome è in uno dei tre: nessun collegamento, collegamento interno o collegamento esterno.
Unità di traduzione diverse possono condividere la stessa dichiarazione mediante l'inclusione del file di intestazione / sorgente (sì, è la formulazione dello standard). Quindi puoi fare riferimento allo stesso nome in diverse unità di traduzione. Se il nome dichiarato ha un collegamento esterno, viene condivisa anche l'identità dell'entità a cui fa riferimento il nome. Se il nome dichiarato ha un collegamento interno, lo stesso nome in unità di traduzione diverse indica entità diverse, ma è possibile fare riferimento all'entità in ambiti diversi della stessa unità di traduzione. Se il nome non ha alcun collegamento, semplicemente non è possibile fare riferimento all'entità da altri ambiti.
(Oops ... ho scoperto che quello che ho digitato era in qualche modo solo ripetendo la formulazione standard ...)
Ci sono anche alcuni altri punti confusi che non sono coperti dalle specifiche della lingua.
__attribute__
o__declspec
) o opzioni del compilatore e l'immagine non è l'intero programma o il file oggetto tradotto da un'unità di traduzione, quindi nessun concetto standard può descriverlo con precisione. Poiché symbol non è un termine normativo in C ++, è solo un dettaglio di implementazione, anche se le relative estensioni dei dialetti potrebbero essere state ampiamente adottate.La regola di collegamento della const
variabile dell'ambito dello spazio dei nomi è qualcosa di speciale (e particolarmente diversa const
dall'oggetto dichiarato nell'ambito del file nel linguaggio C che ha anche il concetto di collegamento degli identificatori). Poiché ODR è applicato da C ++, è importante mantenere non più di una definizione della stessa variabile o funzione presente nell'intero programma, ad eccezione delle inline
funzioni . Se non esiste una regola così speciale di const
, una più semplice dichiarazione di const
variabile con inizializzatori (ad esempio = xxx
) in un'intestazione o in un file di origine (spesso un "file di intestazione") incluso da più unità di traduzione (o incluso da un'unità di traduzione più di una volta, anche se raramente) in un programma violerà ODR, che fa usareconst
variabile come impossibile la sostituzione di alcune macro simili ad oggetti.
Penso che il collegamento interno ed esterno in C ++ fornisca una spiegazione chiara e concisa:
Un'unità di traduzione fa riferimento a un file di implementazione (.c / .cpp) e a tutti i file di intestazione (.h / .hpp) che include. Se un oggetto o una funzione all'interno di tale unità di traduzione ha un collegamento interno, quel simbolo specifico è visibile solo al linker all'interno di tale unità di traduzione. Se un oggetto o una funzione ha un collegamento esterno, il linker può anche vederlo durante l'elaborazione di altre unità di traduzione. La parola chiave statica, quando utilizzata nello spazio dei nomi globale, impone a un simbolo di avere un collegamento interno. La parola chiave extern genera un simbolo con collegamento esterno.
Il compilatore imposta automaticamente il collegamento di simboli in modo che:
Le variabili globali non cost hanno un collegamento esterno per impostazione predefinita Le
variabili globali Const hanno un collegamento interno per impostazione predefinita Le
funzioni hanno un collegamento esterno per impostazione predefinita
Il collegamento determina se identificatori con nomi identici si riferiscono allo stesso oggetto, funzione o altra entità, anche se tali identificatori compaiono in unità di traduzione diverse. Il collegamento di un identificatore dipende da come è stato dichiarato. Esistono tre tipi di collegamenti:
Solo C ++ : puoi anche avere un collegamento tra frammenti di codice C ++ e non C ++, che si chiama collegamento linguistico .
Fonte: IBM Program Linkage
Fondamentalmente
extern linkage
la variabile è visibile in tutti i fileinternal linkage
la variabile è visibile in un singolo file.Spiega: le variabili const si collegano internamente per impostazione predefinita se non diversamente dichiarato come esterno
external linkage
const
la variabile globale èinternal linkage
extern const
la variabile globale èexternal linkage
Un materiale abbastanza buono sul collegamento in C ++
http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/
In C ++
Qualsiasi variabile nell'ambito del file e che non è nidificata all'interno di una classe o di una funzione, è visibile in tutte le unità di traduzione in un programma. Questo si chiama linkage esterno perché al momento del link il nome è visibile dappertutto sul linker, esterno a quell'unità di traduzione.
Le variabili globali e le funzioni ordinarie hanno un collegamento esterno.
L' oggetto statico o il nome della funzione nell'ambito del file è locale all'unità di traduzione. Questo è chiamato collegamento interno
Il collegamento si riferisce solo agli elementi che hanno indirizzi al momento del collegamento / caricamento; pertanto, le dichiarazioni di classe e le variabili locali non hanno alcun collegamento.