¿Qué es el enlace externo y el enlace interno?

337

Quiero entender el enlace externo y el enlace interno y su diferencia.

También quiero saber el significado de

constLas variables se vinculan internamente por defecto a menos que se declare lo contrario extern.

rkb
fuente

Respuestas:

279

Cuando se escribe un archivo de aplicación ( .cpp, .cxx, etc.) el compilador genera una unidad de traducción . Este es el archivo fuente de su implementación más todas las cabeceras que #includeincluyó en él.

Enlace interno se refiere a todo solo en el alcance de una unidad de traducción .

La vinculación externa se refiere a cosas que existen más allá de una unidad de traducción particular. En otras palabras, accesible a través de todo el programa , que es la combinación de todas las unidades de traducción (o archivos de objetos).

amigo
fuente
112
Votaría esto a excepción de una falla: una unidad de traducción no es "de alguna manera el archivo objeto", es el código fuente desde el cual el compilador crea el archivo objeto.
sbi
44
@FrankHB, ¿cuál es el "algo más importante" que falta la respuesta?
Matemático
2
@Mathematician Lo siento por llegar tarde ... Creo que el problema debería ser obvio (además de la precisión de la redacción). Esta respuesta es incompleta, ya que la pregunta sobre la regla de las constvariables (así como su propósito) se pierde por completo aquí.
FrankHB
294

Como dudewat, dicho enlace externo significa que el símbolo (función o variable global) es accesible a través de su programa y el enlace interno significa que solo es accesible en una unidad de traducción .

Puede controlar explícitamente el enlace de un símbolo utilizando las palabras clave externy static. Si no se especifica el enlace, el enlace predeterminado es externpara los que no son constsímbolos y static(interno) para los constsímbolos.

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

Tenga en cuenta que en lugar de usar staticpara enlaces internos, es mejor usar espacios de nombres anónimos en los que también puede poner classes. El enlace para espacios de nombres anónimos ha cambiado entre C ++ 98 y C ++ 11, pero lo principal es que no se puede acceder desde otras unidades de traducción.

namespace {
   int i; // external linkage but unreachable from other translation units.
   class invisible_to_others { };
}
Motti
fuente
11
La implementación de la palabra clave "exportar" destacó una diferencia entre una función declarada 'estática' y una función declarada en el espacio de nombres sin nombre. Para resumir lo mejor que puedo, una plantilla de función declarada con la palabra clave de exportación en una unidad de traducción puede hacer referencia a una función definida en un espacio de nombres sin nombre de una unidad de traducción diferente como resultado de una búsqueda de 2 fases. ( ddj.com/showArticle.jhtml?articleID=184401584 )
Richard Corden
¿Qué sucede si hago lo siguiente? 1.cpp <code> const int ci; </code> 2.cpp <code> extern const int ci; </code>
Rajendra Uppal
2
@Rajenda obtendrá un error de símbolo sin resolver (perdón por el retraso de nueve meses en responder, perdí este comentario).
Motti
44
Información que podría mejorar en gran medida esta respuesta: 1) static ya no está en desuso en C ++ 11. 2) los miembros anónimos del espacio de nombres en C ++ 11 tienen un enlace interno por defecto. Ver stackoverflow.com/questions/10832940/…
Klaim
2
¿Qué significa "enlace externo pero inalcanzable desde otras unidades de traducción"? ¿Cómo puede ser inalcanzable pero aún externo?
szx
101
  • Una variable global tiene un enlace externo por defecto. Su alcance puede extenderse a otros archivos además de contenerlo mediante una externdeclaración coincidente en el otro archivo.
  • El alcance de una variable global se puede restringir al archivo que contiene su declaración prefijando la declaración con la palabra clave static. Dichas variables se dice que tienen enlace interno .

Considere el siguiente ejemplo:

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 de la función se fdeclara fcomo una función con enlace externo (predeterminado). Su definición se debe proporcionar más adelante en este archivo o en otra unidad de traducción (se proporciona a continuación).
  2. maxse define como una constante entera. El enlace predeterminado para las constantes es interno . Su enlace se cambia a externo con la palabra clave extern. Entonces ahora maxse puede acceder en otros archivos.
  3. nse define como una variable entera. El enlace predeterminado para las variables definidas fuera de los cuerpos de función es externo .

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. maxse declara que tiene enlace externo . maxDebe aparecer una definición coincidente para (con enlace externo) en algún archivo. (Como en 1.cpp)
  2. nse declara que tiene enlace externo .
  3. zse define como una variable global con enlace interno .
  4. La definición de nCallespecifica nCallque es una variable que retiene su valor en las llamadas a la función f(). A diferencia de las variables locales con la clase de almacenamiento automático predeterminada, nCallse inicializarán solo una vez al inicio del programa y no una vez por cada invocación de f(). El especificador de clase de almacenamiento staticafecta la vida útil de la variable local y no su alcance.

NB: la palabra clave staticjuega un doble papel. Cuando se usa en las definiciones de variables globales, especifica el enlace interno . Cuando se usa en las definiciones de las variables locales, especifica que la vida útil de la variable será la duración del programa en lugar de ser la duración de la función.

¡Espero que ayude!

Rajendra Uppal
fuente
2
Es importante destacar que, cuando se usa en las definiciones de variables locales, staticpermite una inicialización simple perezosa (que puede ser útil si necesita un objeto global-ish pero tiene que controlar cuándo se construye debido a problemas con el orden de construcción global y no puede asignarlo dinámicamente) el uso de newesquemas de inicialización más profundos puede estar más allá de lo necesario para el objeto en cuestión; por implicación, esto es principalmente un problema en los sistemas integrados que usan C ++).
JAB
1
Muy bien Examle, me alegró el día.
Blood-HaZaRd
28

En términos de 'C' (porque la palabra clave estática tiene un significado diferente entre 'C' y 'C ++')

Hablemos de diferentes alcances en 'C'

ALCANCE: Básicamente es cuánto tiempo puedo ver algo y qué tan lejos.

  1. Variable local: el alcance solo está dentro de una función. Reside en el área STACK de RAM. Lo que significa que cada vez que se llama a una función, todas las variables que forman parte de esa función, incluidos los argumentos de la función, se crean recientemente y se destruyen una vez que el control sale de la función. (Debido a que la pila se vacía cada vez que regresa la función)

  2. Variable estática: el alcance de esto es para un archivo. Es accesible desde cualquier lugar del archivo
    en el que se declara. Reside en el segmento de DATOS de RAM. Dado que esto solo se puede acceder dentro de un archivo y, por lo tanto, enlace interno. Cualquier
    otro archivo no puede ver esta variable. De hecho, la palabra clave STATIC es la única forma en que podemos introducir algún nivel de datos o función que se
    oculta en 'C'

  3. Variable global: el alcance de esto es para una aplicación completa. Es accesible desde cualquier lugar de la aplicación. Las variables globales también residen en el segmento DATOS, ya que se puede acceder a todas las partes de la aplicación y, por lo tanto, a la vinculación EXTERNA

Por defecto, todas las funciones son globales. En caso de que necesite ocultar algunas funciones en un archivo desde el exterior, puede anteponer la palabra clave estática a la función. :-)

Libin Jose
fuente
12
@Libin: en cuanto a 1) las variables locales no tienen que estar en la pila, generalmente están en la pila, pero pueden estar en registros y en el entorno ARM están más a menudo en registros que en la pila (depende de algunos factores: nivel de llamada, número de argumentos formales ..)
Artur
44
@Libin: En cuanto a 1) Si considera 'flush' como sobrescribir, esto está mal. El puntero de la pila simplemente se mueve a un lugar diferente. No hay 'vars locales previamente válidos' que se 'vacíen' / borren, etc. Combina el alcance variable con la duración del almacenamiento. El alcance indica desde dónde puede acceder a una var. La duración del almacenamiento indica cuánto tiempo existe. Puede tener una variable local con una duración de almacenamiento estático. Significa que vive "para siempre" pero se puede acceder desde una función en la que se declara.
Artur
2
Voto negativo por conceptos inexactos y conceptos erróneos obvios. Estrictamente hablando, no hay una definición "global" ni "variable" (como sustantivo) definida en C. Probablemente desee referirse a "objeto de alcance de archivo" en lugar de "variable global", pero hablando de "alcance" (en C it es una propiedad de un identificador ) de eso no tiene sentido. (Ambos términos se definen en C ++ normativamente con significados ligeramente diferentes.)
FrankHB
@Artur Creo que habías olvidado el " único " en " Significa que vive" para siempre "pero se puede acceder (solo) desde una función en la que se declara ". Este es un detalle importante, por lo tanto, me gustaría señalar eso explícitamente.
RobertS apoya a Monica Cellio
14

Antes de hablar sobre la pregunta, es mejor conocer el término unidad de traducción , programa y algunos conceptos básicos de C ++ (en realidad, el enlace es uno de ellos en general) con precisión. También tendrá que saber qué es un alcance .

Destacaré algunos puntos clave, especialmente. los que faltan en respuestas anteriores.

La vinculación es una propiedad de un nombre , que se introduce mediante una declaración . Diferentes nombres pueden denotar la misma entidad (típicamente, un objeto o una función). Por lo tanto, hablar sobre la vinculación de una entidad generalmente no tiene sentido, a menos que esté seguro de que la entidad solo se referirá con el nombre único de algunas declaraciones específicas (por lo general, una declaración).

Tenga en cuenta que un objeto es una entidad, pero una variable no lo es. Al hablar sobre el enlace de una variable, en realidad se refiere al nombre de la entidad denotada (que se introduce mediante una declaración específica). El enlace del nombre se encuentra en uno de los tres: sin enlace, enlace interno o enlace externo.

Las diferentes unidades de traducción pueden compartir la misma declaración por encabezado / archivo fuente (sí, es la redacción del estándar) inclusión. Entonces puede referir el mismo nombre en diferentes unidades de traducción. Si el nombre declarado tiene un enlace externo, también se comparte la identidad de la entidad referida por el nombre. Si el nombre declarado tiene un enlace interno, el mismo nombre en diferentes unidades de traducción denota diferentes entidades, pero puede referir la entidad en diferentes ámbitos de la misma unidad de traducción. Si el nombre no tiene vinculación, simplemente no puede referir la entidad desde otros ámbitos.

(Vaya ... descubrí que lo que escribí fue algo así como repetir la redacción estándar ...)

También hay otros puntos confusos que no están cubiertos por la especificación del idioma.

  1. Visibilidad (de un nombre). También es una propiedad de nombre declarado, pero con un significado diferente al enlace .
  2. Visibilidad (de un efecto secundario) . Esto no está relacionado con este tema.
  3. Visibilidad (de un símbolo). Esta noción puede ser utilizada por implementaciones reales . En tales implementaciones, un símbolo con visibilidad específica en el código de objeto (binario) suele ser el objetivo mapeado de la definición de entidad cuyos nombres tienen el mismo enlace específico en el código fuente (C ++). Sin embargo, por lo general no se garantiza uno a uno. Por ejemplo, un símbolo en una imagen de biblioteca dinámica se puede especificar solo compartido en esa imagen internamente desde el código fuente (involucrado con algunas extensiones, típicamente, __attribute__o__declspec) u opciones del compilador, y la imagen no es todo el programa o el archivo objeto traducido desde una unidad de traducción, por lo que ningún concepto estándar puede describirlo con precisión. Dado que símbolo no es un término normativo en C ++, es solo un detalle de implementación, a pesar de que las extensiones relacionadas de dialectos pueden haber sido ampliamente adoptadas.
  4. Accesibilidad. En C ++, generalmente se trata de la propiedad de los miembros de la clase o las clases base , que nuevamente es un concepto diferente no relacionado con el tema.
  5. Global. En C ++, "global" se refiere a algo de espacio de nombres global o alcance de espacio de nombres global. Este último es aproximadamente equivalente al alcance del archivo en el lenguaje C. Tanto en C como en C ++, el enlace no tiene nada que ver con el alcance, aunque el alcance (como el enlace) también está estrechamente relacionado con un identificador (en C) o un nombre (en C ++) introducido por alguna declaración.

La regla de vinculación de la constvariable de alcance del espacio de nombres es algo especial (y particularmente diferente al constobjeto declarado en el alcance del archivo en lenguaje C que también tiene el concepto de vinculación de identificadores). Dado que C ++ aplica ODR , es importante mantener no más de una definición de la misma variable o función que se produjo en todo el programa, excepto para las inlinefunciones . Si no existe dicha regla especial de const, una declaración de constvariable más simple con inicializadores (p = xxx. Ej. ) En un encabezado o un archivo fuente (a menudo un "archivo de encabezado") incluido por varias unidades de traducción (o incluido por una unidad de traducción más de una vez, aunque rara vez) en un programa violará ODR, lo que hace que el usoconst variable como el reemplazo de algunas macros similares a objetos es imposible.

FrankHB
fuente
3
Esta respuesta suena muy competente y puede ser muy exacta (no puedo juzgar eso), pero lo más probable es que no sea tan comprensible como lo desean muchas de las personas que buscan esta pregunta aquí en lugar de leer directamente las especificaciones del idioma. Al menos para mis necesidades, seguiré con la respuesta aceptada, pero aún así, gracias por dar una pequeña idea de las especificaciones del idioma. 👍🏻
wedi
8

Creo que la vinculación interna y externa en C ++ da una explicación clara y concisa:

Una unidad de traducción se refiere a un archivo de implementación (.c / .cpp) y todos los archivos de encabezado (.h / .hpp) que incluye. Si un objeto o función dentro de dicha unidad de traducción tiene un enlace interno, entonces ese símbolo específico solo es visible para el enlazador dentro de esa unidad de traducción. Si un objeto o función tiene un enlace externo, el enlazador también puede verlo al procesar otras unidades de traducción. La palabra clave estática, cuando se usa en el espacio de nombres global, obliga a un símbolo a tener un enlace interno. La palabra clave externa da como resultado un símbolo que tiene un enlace externo.

El compilador predetermina el enlace de símbolos de manera que:

Las variables globales no constantes tienen un vínculo externo por defecto Las variables globales no constantes tienen un vínculo
interno por defecto Las
funciones tienen un vínculo externo por defecto

Nan Xiao
fuente
6

La vinculación determina si los identificadores que tienen nombres idénticos se refieren al mismo objeto, función u otra entidad, incluso si esos identificadores aparecen en diferentes unidades de traducción. El enlace de un identificador depende de cómo se declaró. Hay tres tipos de enlaces:

  1. Enlace interno : los identificadores solo se pueden ver dentro de una unidad de traducción.
  2. Enlace externo : los identificadores se pueden ver (y consultar) en otras unidades de traducción.
  3. Sin vinculación : los identificadores solo se pueden ver en el ámbito en el que se definen. La vinculación no afecta el alcance

Solo C ++ : también puede tener una vinculación entre fragmentos de código C ++ y no C ++, lo que se denomina vinculación de lenguaje .

Fuente: Enlace de programa de IBM

arun pal
fuente
5

Básicamente

  • extern linkage variable es visible en todos los archivos
  • internal linkage La variable es visible en un solo archivo.

Explique: las variables const se vinculan internamente de forma predeterminada a menos que se declare como externo

  1. por defecto, la variable global es external linkage
  2. pero, constla variable global esinternal linkage
  3. extra, extern constla variable global esexternal linkage

Un material bastante bueno sobre vinculación en C ++

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

Color
fuente
1

En C ++

Cualquier variable en el alcance del archivo y que no esté anidada dentro de una clase o función, es visible en todas las unidades de traducción de un programa. Esto se llama enlace externo porque en el momento del enlace el nombre es visible para el enlazador en todas partes, externo a esa unidad de traducción.

Las variables globales y las funciones ordinarias tienen un enlace externo.

El objeto estático o el nombre de la función en el alcance del archivo es local para la unidad de traducción. Eso se llama Enlace interno

La vinculación se refiere solo a elementos que tienen direcciones en el enlace / tiempo de carga; por lo tanto, las declaraciones de clase y las variables locales no tienen vinculación.

Saurabh Raoot
fuente
const global vars tienen enlace interno.
Blood-HaZaRd