Articulo de referencia

Enlace (software)

En programación, el enlace describe cómo los nombres pueden o no referirse a la misma entidad a lo largo de todo el programa o de una única unidad de traducción . La static pala...

En programación, el enlace describe cómo los nombres pueden o no referirse a la misma entidad a lo largo de todo el programa o de una única unidad de traducción .

La staticpalabra clave `namespace` se usa en C para restringir la visibilidad de una función o variable a su unidad de traducción. Esto también es válido en C++ . C++98 y C++03 desaconsejaron este uso en favor de los espacios de nombres anónimos , pero ya no está desaconsejado en C++11 . Además, C++ trata implícitamente cualquier constvariable con ámbito de espacio de nombres como si tuviera enlace interno a menos que se declare explícitamente extern, a diferencia de C.

El enlace de un nombre está relacionado con su ámbito , pero es distinto . El ámbito de un nombre es la parte de una unidad de traducción donde es visible. Por ejemplo, un nombre con ámbito global (que es lo mismo que el ámbito de archivo en C y el ámbito de espacio de nombres global en C++) es visible en cualquier parte del archivo. Su ámbito terminará al final de la unidad de traducción, independientemente de si ese nombre tiene un enlace externo o interno.

Si el nombre tiene enlace externo, la entidad que denota ese nombre puede ser referenciada desde otra unidad de traducción usando una declaración distinta para ese mismo nombre, y desde otros ámbitos dentro de la misma unidad de traducción usando declaraciones distintas. Si el nombre tuviera enlace interno, dicha declaración denotaría una entidad distinta, aunque usando el mismo nombre, pero su entidad podría ser referenciada por declaraciones distintas dentro de la misma unidad de traducción. Un nombre que no tiene ningún enlace no puede ser referenciado desde declaraciones en diferentes ámbitos, ni siquiera dentro de la misma unidad de traducción. Ejemplos de tales nombres son los parámetros de funciones y las variables locales. Los detalles difieren entre C (donde solo los objetos y las funciones, pero no los tipos, tienen enlace) y C++ y entre esta descripción general simplificada.

La vinculación entre lenguajes debe hacerse con cuidado, ya que cada lenguaje utiliza símbolos externos de forma diferente. Un modismo común es vincular código C++ y C.extern"C"

do

Definición de "enlace" citada de ISO/IEC 9899:TC3 (Estándar C99). C utiliza el término "identificador" donde este artículo utiliza "nombre" (este último es el que C++ utiliza para formalizar el enlace):

Un identificador declarado en diferentes ámbitos o en el mismo ámbito más de una vez puede hacerse referencia al mismo objeto o función mediante un proceso llamado enlace. [ 1 ]

El siguiente es un ejemplo común de vinculación:

En demo1.c :

// El calificador "extern" es opcional // Por defecto, las funciones tienen enlace externo /* extern */ void foo ( void ); int main ( void ) { foo (); return 0 ; }

En demo2.c :

void foo ( void ) { // implementación real aquí... }

La función foo()se declara en dos archivos, con su cuerpo definido en demo2.c . Mediante enlace, la llamada en demo1.c hace referencia a la llamada en demo2.c . Este es un ejemplo de enlace externo para una función.foo()main()foo

Vinculación de código C y C++

Si bien C y C++ mantienen un alto grado de compatibilidad de código fuente, los archivos objeto que producen sus respectivos compiladores pueden presentar diferencias importantes que se manifiestan al mezclar código C y C++. En particular:

  • Los compiladores de C no nombran los símbolos mangle de la misma manera que lo hacen los compiladores de C++. [ 2 ]
  • Dependiendo del compilador y la arquitectura, también puede darse el caso de que las convenciones de llamada difieran entre los dos lenguajes.

Por estas razones, para que el código C++ llame a una función C foo(), el código C++ debe prototiparfoo() con . Del mismo modo, para que el código C llame a una función C++ , el código C++ para debe declararse con .extern"C"bar()bar()extern"C"

Una práctica común para los archivos de cabecera para mantener la compatibilidad con C y C++ es hacer que su declaración sea para el ámbito de la cabecera: [ 3 ]extern"C"

En foo.h :

// Si se trata de un compilador de C++, utilice el enlace de C #ifdef __cplusplus extern "C" { #endif// Cualquier símbolo declarado aquí obtiene enlace C void foo (); int bar ( int a , int b );// Si se trata de un compilador de C++, finaliza el enlace con C #ifdef __cplusplus } #endif

Las diferencias entre las convenciones de enlace y llamada de C y C++ también pueden tener implicaciones sutiles para el código que utiliza punteros a funciones . Algunos compiladores producirán código que no funciona si un puntero a función declarado apunta a una función de C++ que no está declarada . [ 4 ]extern"C"extern"C"

Por ejemplo, el siguiente código:

void qux ();extern "C" void foo ( void ( * fp )( void ));barra vacía () {foo ( qux );}

Al usar el compilador C++ de Sun Microsystems , puede aparecer la siguiente advertencia:

"test.cpp", línea 5: Advertencia (anacronismo): El argumento formal fp de tipo extern "C" void(*)() en la llamada a foo(extern "C" void(*)()) se está pasando void(*)().

Esto se debe a que qux()no se declara con las convenciones de enlace y llamada de C, sino que se pasa a la función de foo()C.

C++

C++ ofrece las siguientes formas de enlace: [ 5 ] [ 6 ]

Sin vínculo

Los nombres sin enlace son aquellos a los que solo se puede hacer referencia desde el ámbito exacto en el que se declaran. Por ejemplo, variables locales , parámetros de funciones y clases locales. [ 6 ]

Enlace interno

Los nombres con enlace interno son aquellos que pueden referenciarse desde cualquier ámbito dentro de la misma unidad de traducción . Con el enlace interno, cada unidad de traducción recibe su propia copia aislada del símbolo. Un símbolo obtiene enlace interno si se declara staticen el ámbito del espacio de nombres . Por defecto, los objetos const, constexpr, y typedeftambién tienen enlace interno. [ 6 ] Sin embargo, usar el inlineespecificador en una constvariable en el ámbito del espacio de nombres le da enlace externo. [ 7 ]

// Los símbolos estáticos reciben enlace interno static int double ( int n ) { return 2 * n ; }// constexpr otorga implícitamente enlace interno constexpr size_t MAX_ATTEMPTS = 3 ;// inline constexpr otorga enlace externo inline constexpr size_t MAX_CONNECTIONS = 100 ;

Enlace externo

Los nombres con enlace externo son aquellos a los que se puede hacer referencia desde cualquier unidad de traducción en todo el programa. [ 8 ] [ 9 ]

// A.cpp int i = 1 ; // Declaración y definición real de i// B.cpp extern int i ; // Declara la existencia de i// C.cpp int i = 2 ; // Error: i ya está definido (en A.cpp) extern int i = 3 ; // Mismo error

Enlace de módulos

Los nombres con enlace de módulo son aquellos que pueden compartirse entre diferentes unidades de traducción, pero solo si pertenecen al mismo módulo . Se puede acceder a dichos símbolos desde cualquier archivo que forme parte del módulo, pero no desde el código que importa ese módulo, a menos que se declare explícitamente export.

Enlace lingüístico

El enlace C se denota con , que desactiva la modificación de nombres de C++ . Permite que los programas C++ se enlacen con bibliotecas compiladas escritas puramente en C, y permite llamar a funciones C++ desde C. El código puede no exponer tipos o características que no estén presentes en C (como clases , plantillas o lanzamiento de excepciones ).extern"C"extern"C"

El enlace de C++ se denota con `<link>` y se utiliza para forzar explícitamente las convenciones de enlace de C++. Esto puede usarse dentro de bloques para forzar que un símbolo tenga enlace de C++. Además, se usa en módulos de C++ para forzar que algo dentro del ámbito del módulo se adjunte al módulo global, permitiendo que los símbolos con enlace interno de un archivo de cabecera sigan adjuntos al módulo.extern"C++"extern"C"

exportar módulo wikipedia.ejemplos.mylib ;export extern "C++" { // Fuerza a que el contenido del encabezado tenga una conexión de módulo global cuando se exporta #include <wikipedia/examples/MyLib.hpp> }

Algunos compiladores pueden admitir enlaces de lenguaje adicionales. Por ejemplo, GCC admite el enlace de Java con , que se utiliza al hacer referencia a código Java compilado por GCJ y se utiliza en código C++ para indicar que un símbolo que se consume proviene de Java. [ 10 ]extern"Java"

Por ejemplo, desde Java:

paquete org.wikipedia.examples ;clase pública Foo { int público agregar ( int a , int b ) { return a + b ; } }

Luego, en C++:

#incluir <gcj/cni.h>// Encabezado generado automáticamente #include <org/wikipedia/examples/Foo.h>usando org :: wikipedia :: ejemplos :: Foo ;extern "Java" { int addThroughJava ( int a , int b ) { Foo * foo = new Foo (); return foo -> add ( a , b ); // Nota: foo no debe eliminarse, ya que es un objeto gestionado por el recolector de basura de Java } }

D

En D , un bloque de código que se pretende declarar como proveniente de otro lenguaje puede marcarse :extern(...)

Óxido

En Rust , se utiliza para marcar el enlace C, y siempre es , ya que Rust no puede garantizar la seguridad de las funciones externas. [ 15 ]extern"C"unsafe

use std :: ffi ::{ CString , c_char };unsafe extern "C" { fn puts ( s : * const c_char ) -> i32 ; }fn main () { let s = CString :: new ( "Hello from Rust!" ). unwrap ();inseguro { puts ( s . as_ptr ()); } }

Mientras tanto, para exponer las funciones de Rust a C:

#[unsafe(no_mangle)] pub extern "C" fn add ( a : i32 , b : i32 ) -> i32 { a + b }

Rust ofrece los siguientes bloques externos: [ 16 ]

  • unsafeextern"Rust"(Convención de llamada predeterminada en Rust)
  • unsafeextern"C"(la ABI de C predeterminada)

Existen otros bloques específicos del sistema, muchos de los cuales corresponden a atributos del compilador C/C++, por ejemplo, correspondientes a .unsafeextern"stdcall"[[gnu::stdcall]]

Véase también

Referencias

  1. ISO/IEC 9899. Documentos oficiales C99, incluyendo correcciones técnicas y una justificación. A partir de 2007, la última versión de la norma es "ISO/IEC 9899:TC3" (PDF) . (3,61 MiB ) 
  2. "Centro de conocimiento de IBM" . ibm.com .
  3. "Centro de conocimiento de IBM" . ibm.com .
  4. "Documentación de Oracle" . Docs.sun.com. Archivado del original el 3 de abril de 2009. Consultado el 18 de agosto de 2013 .
  5. cppreference.com. "Especificadores de clase de almacenamiento" . cppreference.com . cppreference.com . Consultado el 18 de mayo de 2026 .
  6. 1 2 3 Microsoft Learn. "Unidades de traducción y vinculación" . learn.microsoft.com . Microsoft Learn . Consultado el 28 de enero de 2025 .
  7. cppreference.com. "especificador en línea" . cppreference.com . cppreference.com . Consultado el 18 de mayo de 2026 .
  8. IBM (8 de abril de 2025). "Enlace externo" . ibm.com . IBM.
  9. Microsoft Learn (3 de diciembre de 2021). "extern (C++)" . learn.microsoft.com . Microsoft Learn.
  10. Proyecto GNU. "7.7 Atributos de variables, funciones y tipos específicos de C++" . gcc.gnu.org . Proyecto GNU . Consultado el 19 de mayo de 2026 .
  11. Fundación del Lenguaje D (18 de mayo de 2026). "Interfaz con C" . dlang.org . Fundación del Lenguaje D.
  12. Fundación del Lenguaje D (18 de mayo de 2026). "Interfaz con C++" . dlang.org . Fundación del Lenguaje D.
  13. Fundación del Lenguaje D (18 de mayo de 2026). "Interfaz con Objective-C" . dlang.org . Fundación del Lenguaje D.
  14. Fundación del Lenguaje D (10 de octubre de 2025). "dmd.mangle - Lenguaje de programación D" . dlang.org . Fundación del Lenguaje D.
  15. Los desarrolladores de Rust (26 de junio de 2026). "Palabra clave extern" . docs.rust-lang.org . Los desarrolladores de Rust.
  16. Los desarrolladores de Rust (25 de junio de 2026). "Bloques externos" . docs.rust-lang.org . Los desarrolladores de Rust.