Qu'est-ce que le lien externe et le lien interne?

337

Je veux comprendre le lien externe et le lien interne et leur différence.

Je veux aussi connaître le sens de

constles variables sont liées en interne par défaut, sauf indication contraire extern.

rkb
la source

Réponses:

279

Lorsque vous écrivez un fichier de mise en œuvre ( .cpp, .cxx, etc.) votre compilateur génère une unité de traduction . Il s'agit du fichier source de votre implémentation et de tous les en-têtes que vous y trouverez #include.

Le lien interne fait référence à tout uniquement dans le cadre d'une unité de traduction .

Le lien externe fait référence à des choses qui existent au-delà d'une unité de traduction particulière. En d'autres termes, accessible via l'ensemble du programme , qui est la combinaison de toutes les unités de traduction (ou fichiers objets).

dudewat
la source
112
Je voterais positivement, sauf pour un problème: une unité de traduction n'est pas "en quelque sorte le fichier objet", c'est le code source à partir duquel le compilateur crée le fichier objet.
sbi
4
@FrankHB, quel est le "quelque chose de plus important" auquel la réponse manque?
Mathématicien
2
@Mathematician Désolé pour la fin ... Je pense que le problème devrait être évident (en plus de l'exactitude de la formulation). Cette réponse est incomplète, car la question sur la règle des constvariables (ainsi que son objectif) est totalement manquée ici.
FrankHB
294

Comme le dit dudewat, le lien externe signifie que le symbole (fonction ou variable globale) est accessible dans tout votre programme et le lien interne signifie qu'il n'est accessible que dans une seule unité de traduction .

Vous pouvez contrôler explicitement la liaison d'un symbole à l'aide des mots clés externet static. Si la liaison n'est pas spécifiée, la liaison par défaut est externpour les non- constsymboles et static(interne) pour les constsymboles.

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

Notez qu'au lieu d'utiliser staticpour la liaison interne, il est préférable d'utiliser des espaces de noms anonymes dans lesquels vous pouvez également placer classes. Le lien pour les espaces de noms anonymes a changé entre C ++ 98 et C ++ 11 mais l'essentiel est qu'ils sont inaccessibles à partir d'autres unités de traduction.

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}
Motti
la source
11
L'implémentation du mot clé "export" a mis en évidence une différence entre une fonction déclarée 'statique' et une fonction déclarée dans l'espace de nom sans nom. Pour résumer le mieux possible, un modèle de fonction déclaré avec le mot-clé d'exportation dans une unité de traduction peut faire référence à une fonction définie dans un espace de nom sans nom d'une unité de traduction différente à la suite d'une recherche en 2 phases. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden
Et si je fais ce qui suit: 1.cpp <code> const int ci; </code> 2.cpp <code> extern const int ci; </code>
Rajendra Uppal
2
@Rajenda, vous obtiendrez une erreur de symbole non résolue (désolé pour le retard de neuf mois dans la réponse, j'ai raté ce commentaire).
Motti
4
Informations qui pourraient grandement améliorer cette réponse: 1) statique n'est plus obsolète en C ++ 11. 2) Les membres anonymes de l'espace de noms en C ++ 11 ont une liaison interne par défaut. Voir stackoverflow.com/questions/10832940/…
Klaim
2
Que signifie «lien externe mais inaccessible à partir d'autres unités de traduction»? Comment peut-il être inaccessible mais toujours externe?
szx
101
  • Une variable globale a un lien externe par défaut. Sa portée peut être étendue à des fichiers autres que le contenant en donnant une externdéclaration correspondante dans l'autre fichier.
  • La portée d'une variable globale peut être limitée au fichier contenant sa déclaration en préfixant la déclaration avec le mot-clé static. Ces variables auraient un lien interne .

Prenons l'exemple suivant:

1.cpp

void f(int i);
extern const int max = 10;
int n = 0;
int main()
{
    int a;
    //...
    f(a);
    //...
    f(a);
    //...
}
  1. La signature de la fonction se fdéclare fcomme une fonction avec une liaison externe (par défaut). Sa définition doit être fournie ultérieurement dans ce fichier ou dans une autre unité de traduction (indiquée ci-dessous).
  2. maxest défini comme une constante entière. Le lien par défaut pour les constantes est interne . Son lien est changé en externe avec le mot-clé extern. Alors maintenant, maxon peut y accéder dans d'autres fichiers.
  3. nest défini comme une variable entière. Le lien par défaut pour les variables définies en dehors des corps de fonction est externe .

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. maxest déclaré avoir un lien externe . Une définition correspondante pour max(avec liaison externe) doit apparaître dans certains fichiers. (Comme dans 1.cpp)
  2. nest déclaré avoir un lien externe .
  3. zest défini comme une variable globale avec un lien interne .
  4. La définition de nCallspécifie nCallêtre une variable qui conserve sa valeur lors des appels à la fonction f(). Contrairement aux variables locales avec la classe de stockage automatique par défaut, nCallsera initialisé une seule fois au démarrage du programme et pas une fois pour chaque appel de f(). Le spécificateur de classe de stockage staticaffecte la durée de vie de la variable locale et non sa portée.

NB: Le mot-clé staticjoue un double rôle. Lorsqu'il est utilisé dans les définitions des variables globales, il spécifie le lien interne . Lorsqu'il est utilisé dans les définitions des variables locales, il spécifie que la durée de vie de la variable va être la durée du programme au lieu d'être la durée de la fonction.

J'espère que cela pourra aider!

Rajendra Uppal
la source
2
Surtout, lorsqu'il est utilisé dans les définitions de variables locales, staticpermet l'initialisation unique paresseuse (ce qui peut être utile si vous avez besoin d'un objet global-ish mais devez contrôler quand il est construit en raison de problèmes avec l'ordre de construction global et ne pouvez pas l'allouer dynamiquement l'utilisation de newschémas d'initialisation plus approfondis peut être au-delà de ce qui est nécessaire pour l'objet en question; par implication, c'est principalement un problème sur les systèmes embarqués qui utilisent C ++).
JAB
1
Très bon exemple, a fait ma journée.
Blood-HaZaRd
28

En termes de «C» (parce que le mot-clé statique a une signification différente entre «C» et «C ++»)

Permet de parler de différentes portées en «C»

PORTÉE: C'est essentiellement combien de temps puis-je voir quelque chose et jusqu'où.

  1. Variable locale: la portée est uniquement à l'intérieur d'une fonction. Il réside dans la zone STACK de RAM. Ce qui signifie que chaque fois qu'une fonction est appelée, toutes les variables qui font partie de cette fonction, y compris les arguments de fonction, sont fraîchement créées et sont détruites une fois que le contrôle quitte la fonction. (Parce que la pile est vidée à chaque retour de la fonction)

  2. Variable statique: la portée de ceci est pour un fichier. Il est accessible partout dans le fichier
    dans lequel il est déclaré. Il réside dans le segment DATA de RAM. Étant donné que cela n'est accessible qu'à l'intérieur d'un fichier et donc d'une liaison INTERNE. Aucun
    autre fichier ne peut voir cette variable. En fait, le mot-clé STATIC est le seul moyen par lequel nous pouvons introduire un certain niveau de données ou de fonction se
    cachant en «C»

  3. Variable globale: la portée de ceci est pour une application entière. Il est accessible partout dans l'application. Les variables globales résident également dans le segment DATA puisqu’elles sont accessibles partout dans l’application et donc la liaison EXTERNE

Par défaut, toutes les fonctions sont globales. Dans le cas, si vous devez masquer certaines fonctions d'un fichier de l'extérieur, vous pouvez préfixer le mot-clé statique à la fonction. :-)

Libin Jose
la source
12
@Libin: Comme pour 1) les variables locales n'ont pas besoin d'être sur la pile - elles sont généralement sur la pile mais peuvent être dans les registres et dans l'environnement ARM elles sont plus souvent dans les registres que sur la pile (dépend de certains facteurs - niveau d'appel, nombre d'arguments formels ..)
Artur
4
@Libin: Comme pour 1) Si vous considérez 'flush' comme écraser - c'est faux. Le pointeur de pile est simplement déplacé vers un endroit différent. Aucune «variable locale précédemment valide» n'est «vidée» / effacée, etc. Vous mélangez la portée variable avec la durée de stockage. La portée indique d'où vous pouvez accéder à une var. La durée de stockage indique sa durée. Vous pouvez avoir une variable locale avec une durée de stockage statique. Cela signifie qu'il vit "pour toujours" mais qu'il est accessible à partir d'une fonction dans laquelle il est déclaré.
Artur
2
Downvote pour les concepts inexacts et les idées fausses évidentes. Strictement parlant, il n'y a pas de "global" ni de "variable" (comme un nom) défini en C. Vous voudrez probablement faire référence à "objet de portée de fichier" plutôt qu'à "variable globale", mais parler de "portée" (en C il est une propriété d'un identifiant ), c'est un non-sens. (Les deux termes sont définis en C ++ de manière normative avec des significations légèrement différentes.)
FrankHB
@Artur Je pense que vous avez oublié le " seulement " dans " Cela signifie qu'il vit" pour toujours "mais est accessible (uniquement) à partir d'une fonction dans laquelle il est déclaré. " - Ceci est un détail important, c'est pourquoi je voudrais souligner cela explicitement.
RobertS soutient Monica Cellio le
14

Avant de parler de la question, il est préférable de connaître précisément le terme unité de traduction , programme et certains concepts de base du C ++ (en fait, le lien est l'un d'entre eux). Vous devrez également savoir ce qu'est une portée .

Je soulignerai certains points clés, en particulier. ceux manquants dans les réponses précédentes.

Lien est une propriété d'un nom , qui est introduit par une déclaration . Différents noms peuvent désigner la même entité (généralement, un objet ou une fonction). Par conséquent, parler de liaison d'une entité est généralement un non-sens, sauf si vous êtes sûr que l'entité ne sera référencée que par le nom unique de certaines déclarations spécifiques (généralement une seule déclaration, cependant).

Notez qu'un objet est une entité, mais pas une variable . En parlant du lien d'une variable, en fait, le nom de l'entité désignée (qui est introduit par une déclaration spécifique) est concerné. Le lien du nom est dans l'un des trois: pas de lien, lien interne ou lien externe.

Différentes unités de traduction peuvent partager la même déclaration par en-tête / fichier source (oui, c'est le libellé de la norme). Vous pouvez donc faire référence au même nom dans différentes unités de traduction. Si le nom déclaré a un lien externe, l'identité de l'entité référencée par le nom est également partagée. Si le nom déclaré a un lien interne, le même nom dans différentes unités de traduction désigne différentes entités, mais vous pouvez référencer l'entité dans différentes étendues de la même unité de traduction. Si le nom n'a pas de lien, vous ne pouvez tout simplement pas référencer l'entité à partir d'autres étendues.

(Oups ... J'ai trouvé que ce que j'avais tapé répétait un peu la formulation standard ...)

Il existe également d'autres points déroutants qui ne sont pas couverts par la spécification de langue.

  1. Visibilité (d'un nom). C'est aussi une propriété de nom déclaré, mais avec une signification différente de celle du lien .
  2. Visibilité (d'un effet secondaire) . Ce n'est pas lié à ce sujet.
  3. Visibilité (d'un symbole). Cette notion peut être utilisée par des implémentations réelles . Dans de telles implémentations, un symbole avec une visibilité spécifique dans le code objet (binaire) est généralement la cible mappée à partir de la définition d'entité dont les noms ont la même liaison spécifique dans le code source (C ++). Cependant, il n'est généralement pas garanti un à un. Par exemple, un symbole dans une image de bibliothèque dynamique peut être spécifié uniquement partagé dans cette image en interne à partir du code source (impliqué dans certaines extensions, généralement, __attribute__ou__declspec) ou les options du compilateur, et l'image n'est pas le programme entier ou le fichier objet traduit à partir d'une unité de traduction, donc aucun concept standard ne peut le décrire avec précision. Le symbole n'étant pas un terme normatif en C ++, il ne s'agit que d'un détail d'implémentation, même si les extensions associées des dialectes peuvent avoir été largement adoptées.
  4. Accessibilité. En C ++, il s'agit généralement de la propriété des membres de classe ou des classes de base , qui est encore une fois un concept différent sans rapport avec le sujet.
  5. Global. En C ++, "global" fait référence à quelque chose d'espace de nom global ou de portée d'espace de nom global.Ce dernier est à peu près équivalent à la portée du fichier en langage C. Tant en C qu'en C ++, la liaison n'a rien à voir avec la portée, bien que la portée (comme la liaison) soit également étroitement liée à un identifiant (en C) ou à un nom (en C ++) introduit par une déclaration.

La règle de liaison de la constvariable de portée d'espace de noms est quelque chose de spécial (et particulièrement différent de l' constobjet déclaré dans la portée de fichier en langage C qui a également le concept de liaison des identificateurs). Étant donné que l' ODR est appliqué par C ++, il est important de ne pas conserver plus d'une définition de la même variable ou fonction dans le programme entier, à l'exception des inlinefonctions . S'il n'y a pas une telle règle spéciale const, une déclaration de constvariable la plus simple avec des initialiseurs (par exemple, la variable comme remplacement de certaines macros de type objet est impossible.= xxx ) dans un en-tête ou un fichier source (souvent un "fichier d'en-tête") inclus par plusieurs unités de traduction (ou inclus par une unité de traduction plus d'une fois, bien que rarement) dans un programme violera ODR, ce qui rend l'utilisationconst

FrankHB
la source
3
Cette réponse semble très compétente et peut être très exacte (je ne peux pas en juger), mais elle n'est probablement pas aussi compréhensible que souhaité par de nombreuses personnes qui recherchent cette question ici au lieu de lire directement la spécification de langue. Au moins pour mes besoins, je m'en tiendrai à la réponse acceptée, mais je vous remercie toujours de donner un petit aperçu de la spécification de la langue. 👍🏻
wedi
8

Je pense que le lien interne et externe en C ++ donne une explication claire et concise:

Une unité de traduction fait référence à un fichier d'implémentation (.c / .cpp) et à tous les fichiers d'en-tête (.h / .hpp) qu'elle inclut. Si un objet ou une fonction à l'intérieur d'une telle unité de traduction a une liaison interne, ce symbole spécifique n'est visible que par l'éditeur de liens au sein de cette unité de traduction. Si un objet ou une fonction a un lien externe, l'éditeur de liens peut également le voir lors du traitement d'autres unités de traduction. Le mot-clé statique, lorsqu'il est utilisé dans l'espace de noms global, force un symbole à avoir une liaison interne. Le mot-clé extern entraîne un symbole ayant un lien externe.

Le compilateur par défaut la liaison de symboles tels que:

Les variables globales non const ont un lien externe par défaut Les
variables globales Const ont un lien interne par défaut Les
fonctions ont un lien externe par défaut

Nan Xiao
la source
6

La liaison détermine si les identifiants qui ont des noms identiques font référence au même objet, fonction ou autre entité, même si ces identifiants apparaissent dans différentes unités de traduction. Le lien d'un identifiant dépend de la façon dont il a été déclaré. Il existe trois types de liens:

  1. Lien interne : les identifiants ne sont visibles que dans une unité de traduction.
  2. Lien externe : les identifiants peuvent être vus (et référencés) dans d'autres unités de traduction.
  3. Pas de lien : les identifiants ne peuvent être vus que dans la portée dans laquelle ils sont définis. La liaison n'affecte pas la portée

C ++ uniquement : vous pouvez également établir une liaison entre des fragments de code C ++ et non C ++, ce qui est appelé liaison de langage .

Source: IBM Program Linkage

arun pal
la source
5

Fondamentalement

  • extern linkage la variable est visible dans tous les fichiers
  • internal linkage variable est visible dans un seul fichier.

Expliquer: les variables const lient en interne par défaut, sauf indication contraire comme extern

  1. par défaut, la variable globale est external linkage
  2. mais, constla variable globale estinternal linkage
  3. extern constla variable globale supplémentaire estexternal linkage

Un assez bon matériel sur la liaison en C ++

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

Couleur
la source
1

En C ++

Toute variable à portée de fichier et qui n'est pas imbriquée dans une classe ou une fonction, est visible dans toutes les unités de traduction d'un programme. C'est ce qu'on appelle un lien externe, car au moment du lien, le nom est visible partout par l'éditeur de liens, externe à cette unité de traduction.

Les variables globales et les fonctions ordinaires ont un lien externe.

L' objet statique ou le nom de fonction à la portée du fichier est local à l'unité de traduction. C'est ce qu'on appelle un lien interne

Le lien se réfère uniquement aux éléments qui ont des adresses au moment du lien / chargement; ainsi, les déclarations de classe et les variables locales n'ont aucun lien.

Saurabh Raoot
la source
const vars globaux ont un lien interne.
Blood-HaZaRd