Was ist externe Verknüpfung und interne Verknüpfung?

337

Ich möchte die externe Verknüpfung und die interne Verknüpfung und ihren Unterschied verstehen.

Ich möchte auch die Bedeutung von wissen

constVariablen werden standardmäßig intern verknüpft, sofern nicht anders angegeben als extern.

rkb
quelle

Antworten:

278

Wenn Sie eine Implementierungsdatei ( ,, usw.) schreiben .cpp, .cxxgeneriert Ihr Compiler eine Übersetzungseinheit . Dies ist die Quelldatei aus Ihrer Implementierung sowie alle darin enthaltenen Header #include.

Interne Verknüpfung bezieht sich auf alles nur im Rahmen einer Übersetzungseinheit .

Externe Verknüpfung bezieht sich auf Dinge, die jenseits einer bestimmten Übersetzungseinheit existieren. Mit anderen Worten, Zugriff über das gesamte Programm , dh die Kombination aller Übersetzungseinheiten (oder Objektdateien).

Dudewat
quelle
112
Ich würde dieses upvote bis auf einen Glitch: Eine Übersetzungseinheit ist nicht „irgendwie die Objektdatei“, es ist der Quellcode , aus dem der Compiler erzeugt die Objektdatei.
sbi
4
@FrankHB, was ist das "etwas Wichtigeres", dass die Antwort fehlt?
Mathematiker
2
@Mathematician Entschuldigung für die späte ... Ich denke, das Problem sollte offensichtlich sein (neben der Genauigkeit der Formulierung). Diese Antwort ist unvollständig, da die Frage nach der Regel der constVariablen (sowie deren Zweck) hier völlig übersehen wird.
FrankHB
293

Wie dudewat sagte, bedeutet externe Verknüpfung, dass das Symbol (Funktion oder globale Variable) in Ihrem gesamten Programm zugänglich ist, und interne Verknüpfung bedeutet, dass nur in einer Übersetzungseinheit darauf zugegriffen werden kann .

Sie können die Verknüpfung eines Symbols mithilfe der Schlüsselwörter externund explizit steuern static. Wenn die Verknüpfung nicht angegeben ist, gilt die Standardverknüpfung externfür Nicht- constSymbole und static(intern) für constSymbole.

// 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 

Beachten Sie, dass es staticfür die interne Verknüpfung besser ist, anonyme Namespaces zu verwenden, in die Sie auch es classeinfügen können. Die Verknüpfung für anonyme Namespaces hat sich zwischen C ++ 98 und C ++ 11 geändert, aber die Hauptsache ist, dass sie von anderen Übersetzungseinheiten nicht erreichbar sind.

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}
Motti
quelle
11
Bei der Implementierung des Schlüsselworts "export" wurde ein Unterschied zwischen einer als "statisch" deklarierten Funktion und einer im unbenannten Namespace deklarierten Funktion hervorgehoben. Um es so gut wie möglich zusammenzufassen, kann eine Funktionsvorlage, die mit dem Schlüsselwort export in einer Übersetzungseinheit deklariert wurde, auf eine Funktion verweisen, die in einem unbenannten Namespace einer anderen Übersetzungseinheit als Ergebnis einer zweiphasigen Suche definiert wurde. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden
Was ist, wenn ich Folgendes tue: 1.cpp <code> const int ci; </ code> 2.cpp <code> extern const int ci; </ code>
Rajendra Uppal
2
@ Rajenda Sie erhalten einen ungelösten Symbolfehler (Entschuldigung für die neunmonatige Verzögerung bei der Beantwortung, ich habe diesen Kommentar verpasst).
Motti
4
Informationen, die diese Antwort erheblich verbessern könnten: 1) Static ist in C ++ 11 nicht mehr veraltet. 2) Anonyme Namespace-Mitglieder in C ++ 11 haben standardmäßig eine interne Verknüpfung. Siehe stackoverflow.com/questions/10832940/…
Klaim
2
Was bedeutet "externe Verknüpfung, aber von anderen Übersetzungseinheiten nicht erreichbar"? Wie kann es unerreichbar und doch extern sein?
Szx
101
  • Eine globale Variable verfügt standardmäßig über eine externe Verknüpfung . Sein Geltungsbereich kann auf andere Dateien als die darin enthaltenen erweitert werden, indem eine übereinstimmende externDeklaration in der anderen Datei angegeben wird.
  • Der Gültigkeitsbereich einer globalen Variablen kann auf die Datei beschränkt werden, die ihre Deklaration enthält, indem der Deklaration das Schlüsselwort vorangestellt wird static. Solche Variablen sollen eine interne Verknüpfung haben .

Betrachten Sie folgendes Beispiel:

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. Die Signatur der Funktion fwird fals Funktion mit externer Verknüpfung deklariert (Standard). Die Definition muss später in dieser Datei oder in einer anderen Übersetzungseinheit (siehe unten) angegeben werden.
  2. maxist als ganzzahlige Konstante definiert. Die Standardverknüpfung für Konstanten ist intern . Die Verknüpfung wird mit dem Schlüsselwort in external geändert extern. So maxkann jetzt in anderen Dateien zugegriffen werden.
  3. nist als ganzzahlige Variable definiert. Die Standardverknüpfung für Variablen, die außerhalb von Funktionskörpern definiert sind, ist extern .

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. maxwird für eine externe Verknüpfung deklariert . Eine passende Definition für max(mit externer Verknüpfung) muss in einer Datei enthalten sein. (Wie in 1.cpp)
  2. nwird für eine externe Verknüpfung deklariert .
  3. zist definiert als eine globale Variable mit interner Bindung .
  4. Die Definition von nCallgibt nCallan, dass es sich um eine Variable handelt, die ihren Wert über Funktionsaufrufe hinweg beibehält f(). Im Gegensatz zu lokalen Variablen mit der Standardklasse für die automatische Speicherung nCallwird sie nur einmal zu Beginn des Programms und nicht einmal bei jedem Aufruf von initialisiert f(). Der Speicherklassenspezifizierer staticbeeinflusst die Lebensdauer der lokalen Variablen und nicht deren Umfang.

NB: Das Schlüsselwort staticspielt eine doppelte Rolle. Bei Verwendung in den Definitionen globaler Variablen wird die interne Verknüpfung angegeben . Bei Verwendung in den Definitionen der lokalen Variablen wird angegeben, dass die Lebensdauer der Variablen die Dauer des Programms und nicht die Dauer der Funktion ist.

Ich hoffe, das hilft!

Rajendra Uppal
quelle
2
Wichtig ist, dass bei Verwendung in den Definitionen lokaler Variablen staticeine verzögerte Einzelinitialisierung möglich ist (was nützlich sein kann, wenn Sie ein globales Objekt benötigen, aber aufgrund von Problemen mit der globalen Konstruktionsreihenfolge steuern müssen, wann es erstellt wird, und es nicht dynamisch zuordnen können Die Verwendung von newdetaillierteren Initialisierungsschemata kann über das hinausgehen, was für das betreffende Objekt erforderlich ist. Dies ist implizit hauptsächlich ein Problem bei eingebetteten Systemen, die C ++ verwenden.
JAB
1
Sehr gutes Beispiel, machte meinen Tag.
Blood-HaZaRd
28

In Bezug auf 'C' (weil das statische Schlüsselwort zwischen 'C' und 'C ++' unterschiedliche Bedeutung hat)

Sprechen wir über verschiedene Bereiche in 'C'

GELTUNGSBEREICH: Es ist im Grunde genommen, wie lange ich etwas sehen kann und wie weit.

  1. Lokale Variable: Der Bereich befindet sich nur innerhalb einer Funktion. Es befindet sich im STACK-Bereich des RAM. Dies bedeutet, dass jedes Mal, wenn eine Funktion aufgerufen wird, alle Variablen, die Teil dieser Funktion sind, einschließlich der Funktionsargumente, neu erstellt und zerstört werden, sobald das Steuerelement die Funktion verlässt. (Weil der Stapel jedes Mal geleert wird, wenn die Funktion zurückkehrt)

  2. Statische Variable: Der Gültigkeitsbereich bezieht sich auf eine Datei. Es ist überall in der Datei zugänglich,
    in der es deklariert ist. Es befindet sich im DATA-Segment des RAM. Da darauf nur innerhalb einer Datei und damit der INTERNEN Verknüpfung zugegriffen werden kann. Jegliche
    andere Dateien können diese Variable nicht sehen. Tatsächlich ist das Schlüsselwort STATIC die einzige Möglichkeit, Daten oder Funktionen einzuführen,
    die in 'C' versteckt sind.

  3. Globale Variable: Der Geltungsbereich gilt für eine gesamte Anwendung. Es ist von jedem Ort der Anwendung aus zugänglich. Globale Variablen befinden sich auch im DATA-Segment, da überall in der Anwendung darauf zugegriffen werden kann und somit EXTERNAL Linkage

Standardmäßig sind alle Funktionen global. Wenn Sie einige Funktionen in einer Datei von außen ausblenden müssen, können Sie der Funktion das statische Schlüsselwort voranstellen. :-)

Libin Jose
quelle
12
@Libin: 1) Lokale Variablen müssen sich nicht auf dem Stapel befinden - sie befinden sich normalerweise auf dem Stapel, können sich jedoch in Registern befinden, und in der ARM-Umgebung befinden sie sich häufiger in Registern als im Stapel (abhängig von einigen Faktoren - Anrufstufe, Nummer von formalen Argumenten ..)
Artur
4
@Libin: Wie für 1) Wenn Sie "Flush" als Überschreiben betrachten, ist dies falsch. Der Stapelzeiger wird nur an eine andere Stelle verschoben. Keine 'zuvor gültigen lokalen Variablen' werden 'gelöscht' / gelöscht usw. Sie mischen den variablen Bereich mit der Speicherdauer. Der Bereich gibt an, von wo aus Sie auf eine Variable zugreifen können. Die Speicherdauer gibt an, wie lange sie vorhanden ist. Sie können eine lokale Variable mit statischer Speicherdauer haben. Es bedeutet, dass es "für immer" lebt, aber über eine Funktion, in der es deklariert ist, zugegriffen werden kann.
Artur
2
Downvote für ungenaue Konzepte und offensichtliche Missverständnisse. Genau genommen ist in C weder "global" noch "Variable" (als Substantiv) definiert. Möglicherweise möchten Sie wahrscheinlich eher auf "Dateibereichsobjekt" als auf "globale Variable" verweisen, sondern auf "Gültigkeitsbereich" (in C it) ist eine Eigenschaft eines Bezeichners ) davon ist Unsinn. (Beide Begriffe sind in C ++ normativ mit leicht unterschiedlichen Bedeutungen definiert.)
FrankHB
@Artur Ich denke, Sie haben das " einzige " in " Es bedeutet, dass es" für immer "lebt, können aber (nur) von einer Funktion aus aufgerufen werden, in der es deklariert ist. " - Dies ist ein wichtiges Detail, daher möchte ich darauf hinweisen das explizit raus.
RobertS unterstützt Monica Cellio
1
@RobertSsupportsMonicaCellio - Sie haben Recht
Artur
14

Bevor Sie über die Frage sprechen, ist es besser, den Begriff Übersetzungseinheit , Programm und einige grundlegende Konzepte von C ++ (tatsächlich ist die Verknüpfung eines davon im Allgemeinen) genau zu kennen. Sie müssen auch wissen, was ein Bereich ist .

Ich werde einige wichtige Punkte hervorheben, insb. diejenigen, die in früheren Antworten fehlen.

Verknüpfung ist eine Eigenschaft eines Namens , die durch eine Deklaration eingeführt wird . Unterschiedliche Namen können dieselbe Entität bezeichnen (normalerweise ein Objekt oder eine Funktion). Es ist also normalerweise Unsinn, über die Verknüpfung einer Entität zu sprechen , es sei denn, Sie sind sicher, dass die Entität nur mit dem eindeutigen Namen aus bestimmten Deklarationen (normalerweise jedoch einer Deklaration) referenziert wird.

Beachten Sie, dass ein Objekt eine Entität ist, eine Variable jedoch nicht. Während über die Verknüpfung einer Variablen gesprochen wird, ist tatsächlich der Name der bezeichneten Entität (die durch eine bestimmte Deklaration eingeführt wird) betroffen. Die Verknüpfung des Namens erfolgt in einer der drei: keine Verknüpfung, interne Verknüpfung oder externe Verknüpfung.

Verschiedene Übersetzungseinheiten können dieselbe Deklaration nach Header- / Quelldatei (ja, dies ist der Wortlaut des Standards) enthalten. Sie können also denselben Namen in verschiedenen Übersetzungseinheiten verwenden. Wenn der deklarierte Name eine externe Verknüpfung aufweist, wird auch die Identität der Entität, auf die sich der Name bezieht, freigegeben. Wenn der deklarierte Name eine interne Verknüpfung aufweist, bezeichnet derselbe Name in verschiedenen Übersetzungseinheiten verschiedene Entitäten. Sie können die Entität jedoch in verschiedenen Bereichen derselben Übersetzungseinheit referenzieren. Wenn der Name keine Verknüpfung aufweist, können Sie die Entität einfach nicht aus anderen Bereichen referenzieren.

(Ups ... Ich habe festgestellt, dass das, was ich eingegeben habe, nur die Standardformulierung wiederholt ...)

Es gibt auch einige andere verwirrende Punkte, die in der Sprachspezifikation nicht behandelt werden.

  1. Sichtbarkeit (eines Namens). Es ist auch eine Eigenschaft mit deklariertem Namen, aber mit einer anderen Bedeutung als die Verknüpfung .
  2. Sichtbarkeit (einer Nebenwirkung) . Dies hat nichts mit diesem Thema zu tun.
  3. Sichtbarkeit (eines Symbols). Dieser Begriff kann von tatsächlichen Implementierungen verwendet werden . In solchen Implementierungen ist ein Symbol mit spezifischer Sichtbarkeit im Objektcode (Binärcode) normalerweise das Ziel, das aus der Entitätsdefinition zugeordnet wird, deren Namen dieselbe spezifische Verknüpfung im Quellcode (C ++) aufweisen. Es ist jedoch in der Regel nicht eins zu eins garantiert. Beispielsweise kann ein Symbol in einem dynamischen Bibliotheksbild angegeben werden, das nur in diesem Bild intern aus dem Quellcode freigegeben wird (normalerweise bei einigen Erweiterungen beteiligt, z.__attribute__ oder__declspec) oder Compileroptionen, und das Bild ist nicht das gesamte Programm oder die Objektdatei, die von einer Übersetzungseinheit übersetzt wurde. Daher kann kein Standardkonzept es genau beschreiben. Da Symbol in C ++ kein normativer Begriff ist, handelt es sich nur um ein Implementierungsdetail, obwohl die damit verbundenen Erweiterungen von Dialekten möglicherweise weit verbreitet sind.
  4. Barrierefreiheit. In C ++ handelt es sich normalerweise um Eigenschaften von Klassenmitgliedern oder Basisklassen , was wiederum ein anderes Konzept ist, das nicht mit dem Thema zusammenhängt.
  5. Global. In C ++ bezieht sich "global" auf einen globalen Namespace oder einen globalen Namespace-Bereich. Letzteres entspricht in etwa dem Dateibereich in der Sprache C. Sowohl in C als auch in C ++ hat die Verknüpfung nichts mit dem Gültigkeitsbereich zu tun, obwohl der Gültigkeitsbereich (wie die Verknüpfung) auch stark mit einem Bezeichner (in C) oder einem Namen (in C ++) befasst ist, der durch eine Deklaration eingeführt wurde.

Die Verknüpfungsvorschrift von Namespacebereich constvariabel ist etwas Besonderes (und vor allem anders als das constObjekt in Dateigültigkeitsbereich in C - Sprache erklärt , die auch das Konzept der Verknüpfung von Identifikatoren hat). Da ODR von C ++ erzwungen wird, ist es wichtig, dass nicht mehr als eine Definition derselben Variablen oder Funktion im gesamten Programm außer den inlineFunktionen beibehalten wird . Wenn es keine solche Sonderregel von gibt const, ist eine einfachste Deklaration von constVariablen mit Initialisierern (zB= xxx ) in einem Header oder einer Quelldatei (häufig eine "Header-Datei"), die von mehreren Übersetzungseinheiten (oder von einer Übersetzungseinheit mehr als einmal) enthalten wird. obwohl selten) in einem Programm wird ODR verletzen, die zu verwenden machtconst Variable als Ersatz einiger objektähnlicher Makros unmöglich.

FrankHB
quelle
3
Diese Antwort klingt sehr kompetent und ist möglicherweise sehr genau (das kann ich nicht beurteilen), aber höchstwahrscheinlich ist sie für viele Leute, die diese Frage hier nachschlagen, nicht so verständlich wie gewünscht, anstatt die Sprachspezifikation direkt zu lesen. Zumindest für meine Bedürfnisse werde ich mich an die akzeptierte Antwort halten, aber ich danke Ihnen trotzdem, dass Sie einen kleinen Einblick in die Sprachspezifikation gegeben haben. 👍🏻
Mi
8

Ich denke, die interne und externe Verknüpfung in C ++ gibt eine klare und präzise Erklärung:

Eine Übersetzungseinheit bezieht sich auf eine Implementierungsdatei (.c / .cpp) und alle darin enthaltenen Headerdateien (.h / .hpp). Wenn ein Objekt oder eine Funktion innerhalb einer solchen Übersetzungseinheit eine interne Verknüpfung aufweist, ist dieses spezifische Symbol nur für den Linker innerhalb dieser Übersetzungseinheit sichtbar. Wenn ein Objekt oder eine Funktion über eine externe Verknüpfung verfügt, kann der Linker diese auch bei der Verarbeitung anderer Übersetzungseinheiten sehen. Das statische Schlüsselwort erzwingt bei Verwendung im globalen Namespace die interne Verknüpfung eines Symbols. Das Schlüsselwort extern führt zu einem Symbol mit externer Verknüpfung.

Der Compiler verwendet standardmäßig die Verknüpfung von Symbolen wie folgt:

Globale Variablen ohne
Konstante haben standardmäßig
eine externe Verknüpfung. Globale Variablen von Konstanten haben standardmäßig eine interne Verknüpfung. Funktionen haben standardmäßig eine externe Verknüpfung

Nan Xiao
quelle
6

Die Verknüpfung bestimmt, ob Bezeichner mit identischen Namen auf dasselbe Objekt, dieselbe Funktion oder eine andere Entität verweisen, selbst wenn diese Bezeichner in verschiedenen Übersetzungseinheiten angezeigt werden. Die Verknüpfung eines Bezeichners hängt davon ab, wie er deklariert wurde. Es gibt drei Arten von Verknüpfungen:

  1. Interne Verknüpfung : Bezeichner können nur innerhalb einer Übersetzungseinheit angezeigt werden.
  2. Externe Verknüpfung : Bezeichner können in anderen Übersetzungseinheiten gesehen (und darauf verwiesen) werden.
  3. Keine Verknüpfung : Bezeichner werden nur in dem Bereich angezeigt, in dem sie definiert sind. Die Verknüpfung hat keinen Einfluss auf das Scoping

Nur C ++ : Sie können auch eine Verknüpfung zwischen C ++ - und Nicht-C ++ - Codefragmenten herstellen, die als Sprachverknüpfung bezeichnet wird .

Quelle: IBM Program Linkage

Arun Kumpel
quelle
5

Grundsätzlich

  • extern linkage Variable ist in allen Dateien sichtbar
  • internal linkage Variable ist in einer einzelnen Datei sichtbar.

Erklären Sie: const-Variablen werden standardmäßig intern verknüpft, sofern nicht anders als extern deklariert

  1. Standardmäßig ist die globale Variable external linkage
  2. aber constglobale Variable istinternal linkage
  3. zusätzliche, extern constglobale Variable istexternal linkage

Ein ziemlich gutes Material zur Verknüpfung in C ++

http://www.goldsborough.me/c/c++/linker/2016/03/30/19-34-25-internal_and_external_linkage_in_c++/

Farbe
quelle
1

In C ++

Jede Variable im Dateibereich, die nicht in einer Klasse oder Funktion verschachtelt ist, ist in allen Übersetzungseinheiten eines Programms sichtbar. Dies wird als externe Verknüpfung bezeichnet, da der Name zum Zeitpunkt der Verknüpfung für den Linker überall außerhalb dieser Übersetzungseinheit sichtbar ist.

Globale Variablen und gewöhnliche Funktionen sind extern verknüpft.

Der statische Objekt- oder Funktionsname im Dateibereich ist lokal für die Übersetzungseinheit. Das nennt man interne Verknüpfung

Die Verknüpfung bezieht sich nur auf Elemente, deren Adressen zum Zeitpunkt der Verknüpfung / Ladung vorliegen. Daher haben Klassendeklarationen und lokale Variablen keine Verknüpfung.

Saurabh Raoot
quelle
const globale vars haben eine interne Verknüpfung.
Blood-HaZaRd