Che cos'è il collegamento esterno e il collegamento interno?


337

Voglio capire il collegamento esterno e il collegamento interno e la loro differenza.

Voglio anche sapere il significato di

constle variabili si collegano internamente per impostazione predefinita se non diversamente indicato come extern.

Risposte:


279

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 #includeinserito.

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).


112
Voterei questo ad eccezione di un problema tecnico: un'unità di traduzione non è "in qualche modo il file oggetto", è il codice sorgente da cui il compilatore crea il file oggetto.
sabato

4
@FrankHB, qual è il "qualcosa di più importante" che manca la risposta?
Matematico,

2
@Mathematician Ci scusiamo per il ritardo ... Penso che il problema dovrebbe essere ovvio (oltre all'accuratezza delle parole). Questa risposta è incompleta, in quanto constqui manca totalmente la domanda sulla regola delle variabili (così come sul suo scopo).
FrankHB,

294

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 externe static. Se il collegamento non è specificato, il collegamento predefinito è externper i non constsimboli e static(interno) per i constsimboli.

// 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 staticper il collegamento interno è meglio utilizzare spazi dei nomi anonimi in cui è anche possibile inserire classes. 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 { };
}

11
L'implementazione della parola chiave "export" ha evidenziato una differenza tra una funzione dichiarata "statica" e una funzione dichiarata nello spazio dei nomi senza nome. Per riassumere come meglio posso, un modello di funzione dichiarato con la parola chiave export in un'unità di traduzione può fare riferimento a una funzione definita in uno spazio dei nomi senza nome di un'unità di traduzione diversa come risultato della ricerca in 2 fasi. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden,

Cosa succede se faccio quanto segue: 1.cpp <code> const int ci; </code> 2.cpp <code> extern const int ci; </code>
Rajendra Uppal,

2
@Rajenda riceverai un errore di simbolo non risolto (scusami per il ritardo di nove mesi nella risposta, ho perso questo commento).
Motti,

4
Informazioni che potrebbero migliorare notevolmente questa risposta: 1) static non è più deprecato in C ++ 11. 2) I membri dello spazio dei nomi anonimi in C ++ 11 hanno un collegamento interno per impostazione predefinita. Vedere stackoverflow.com/questions/10832940/...
Klaim

2
Che cosa significa "collegamento esterno ma non raggiungibile da altre unità di traduzione"? Come può essere irraggiungibile ma ancora esterno?
szx,

101
  • Una variabile globale ha un collegamento esterno per impostazione predefinita. Il suo ambito può essere esteso a file diversi da quelli che lo contengono dando una externdichiarazione corrispondente nell'altro file.
  • L'ambito di una variabile globale può essere limitato al file contenente la sua dichiarazione prefissando la dichiarazione con la parola chiave static. Si dice che tali variabili abbiano un collegamento interno .

Prendi in considerazione il seguente esempio:

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. La firma della funzione fdichiara fcome 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).
  2. 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 è maxpossibile accedere in altri file.
  3. nè definito come una variabile intera. Il collegamento predefinito per le variabili definite all'esterno dei corpi funzione è esterno .

2.cpp

#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;
}
  1. maxviene dichiarato di avere un collegamento esterno . Una definizione corrispondente per max(con collegamento esterno) deve apparire in alcuni file. (Come in 1.cpp)
  2. nviene dichiarato di avere un collegamento esterno .
  3. zè definito come una variabile globale con collegamento interno .
  4. La definizione di nCallspecifica nCalldi 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, nCallverranno inizializzati solo una volta all'inizio del programma e non una volta per ogni chiamata di f(). L'identificatore della classe di archiviazione staticinfluisce sulla durata della variabile locale e non sul suo ambito.

NB: la parola chiave ha staticun 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!


2
È importante sottolineare che, quando utilizzato nelle definizioni delle variabili locali, staticconsente 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 newmentre 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 ++).
JAB

1
Very Good Examle, ha reso la mia giornata.
Blood-HaZaRd

28

In termini di "C" (poiché la parola chiave statica ha un significato diverso tra "C" e "C ++")

Parliamo di diversi scopi in 'C'

CAMPO DI APPLICAZIONE: Fondamentalmente è quanto posso vedere qualcosa e quanto lontano.

  1. 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)

  2. 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'

  3. 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. :-)


12
@Libin: come per 1) le variabili locali non devono essere nello stack - di solito sono nello stack ma possono essere nei registri e nell'ambiente ARM sono più spesso nei registri che nello stack (dipende da alcuni fattori - livello di chiamata, numero di argomenti formali ..)
Artur

4
@Libin: quanto a 1) Se consideri 'flush' come sovrascrittura - questo è sbagliato. Il puntatore dello stack viene spostato in un'altra posizione. Nessun 'var locale locale valido in precedenza' viene 'svuotato' / cancellato ecc. Si mescola l'ambito variabile con la durata della memoria. Scope indica da dove è possibile accedere a una var. La durata della memoria indica per quanto tempo esiste. È possibile avere una variabile locale con durata di archiviazione statica. Significa che vive "per sempre" ma è possibile accedervi da una funzione in cui è dichiarata.
Artur

2
Downvote per concetti imprecisi e idee sbagliate evidenti. A rigor di termini, non esiste una "globale" né una "variabile" (come un nome) definita in C. Potresti probabilmente fare riferimento a "oggetto ambito file" anziché "variabile globale", ma parlando di "ambito" (in C esso è una proprietà di un identificatore ) e non ha senso. (Entrambi i termini sono definiti in C ++
normalmente

@Artur Penso che avresti dimenticato "l' unico " in " Significa che vive" per sempre "ma è possibile accedervi (solo) da una funzione in cui è dichiarato. " - Questo è un dettaglio importante, quindi vorrei sottolineare quello esplicitamente.
RobertS supporta Monica Cellio il

14

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.

  1. Visibilità (di un nome). È anche una proprietà del nome dichiarato, ma con un significato diverso dal collegamento .
  2. Visibilità (di un effetto collaterale) . Questo non è correlato a questo argomento.
  3. Visibilità (di un simbolo). Questa nozione può essere utilizzata dalle implementazioni effettive . In tali implementazioni, un simbolo con visibilità specifica nel codice oggetto (binario) è in genere la destinazione mappata dalla definizione dell'entità i cui nomi hanno lo stesso collegamento specifico nel codice sorgente (C ++). Tuttavia, di solito non è garantito uno a uno. Ad esempio, un simbolo in un'immagine di libreria dinamica può essere specificato solo condiviso in quell'immagine internamente dal codice sorgente (coinvolto con alcune estensioni, in genere, __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.
  4. Accessibilità. In C ++, di solito si tratta della proprietà dei membri della classe o delle classi di base , che è di nuovo un concetto diverso non correlato all'argomento.
  5. Globale. In C ++, "globale" fa riferimento a qualcosa dello spazio dei nomi globale o dell'ambito dello spazio dei nomi globale. Quest'ultimo è all'incirca equivalente all'ambito dei file nel linguaggio C. Sia in C che in C ++, il collegamento non ha nulla a che fare con l'ambito, sebbene l'ambito (come il collegamento) sia anche strettamente interessato a un identificatore (in C) o un nome (in C ++) introdotto da alcune dichiarazioni.

La regola di collegamento della constvariabile dell'ambito dello spazio dei nomi è qualcosa di speciale (e particolarmente diversa constdall'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 inlinefunzioni . Se non esiste una regola così speciale di const, una più semplice dichiarazione di constvariabile 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.


3
Questa risposta sembra molto competente e potrebbe essere molto esatta (non posso giudicarlo) ma molto probabilmente non è comprensibile come desiderato da molte persone che cercano questa domanda qui invece di leggere direttamente le specifiche della lingua. Almeno per le mie esigenze, rimarrò fedele alla risposta accettata, ma ti ringrazio ancora per aver dato una piccola visione delle specifiche della lingua. 👍🏻
wedi,

8

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


6

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:

  1. Collegamento interno : gli identificatori possono essere visti solo all'interno di un'unità di traduzione.
  2. Collegamento esterno : gli identificatori possono essere visti (e citati) in altre unità di traduzione.
  3. Nessun collegamento : gli identificatori possono essere visti solo nell'ambito in cui sono definiti. Il collegamento non influisce sull'ambito

Solo C ++ : puoi anche avere un collegamento tra frammenti di codice C ++ e non C ++, che si chiama collegamento linguistico .

Fonte: IBM Program Linkage


5

Fondamentalmente

  • extern linkage la variabile è visibile in tutti i file
  • internal linkage la variabile è visibile in un singolo file.

Spiega: le variabili const si collegano internamente per impostazione predefinita se non diversamente dichiarato come esterno

  1. per impostazione predefinita, la variabile globale è external linkage
  2. ma, constla variabile globale èinternal linkage
  3. extra, extern constla 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++/


1

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.


const global vars ha un collegamento interno.
Blood-HaZaRd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.