Namespaces
Variants

Language linkage

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Proporciona enlace entre unidades de programa escritas en diferentes lenguajes de programación.

Esto también puede utilizarse para separar una declaración de su módulo. Consulte Module ownership .

(since C++20)
extern string-literal { declaration-seq  (opcional) } (1)
extern string-literal declaration (2)
1) Aplica la especificación de lenguaje string-literal a todos los tipos de función, nombres de función con enlace externo y variables con enlace externo declarados en declaration-seq .
2) Aplica la especificación del lenguaje string-literal a una única declaración o definición.
string-literal - un literal de cadena no evaluado que nombra el enlace de lenguaje requerido
declaration-seq - una secuencia de declaraciones, que puede incluir especificaciones de enlace anidadas
declaration - una declaración

Contenidos

Explicación

Cada tipo de función, cada nombre de función con enlace externo , y cada nombre de variable con enlace externo , tiene una propiedad llamada enlace de lenguaje . El enlace de lenguaje encapsula el conjunto de requisitos necesarios para enlazar con una unidad de programa escrita en otro lenguaje de programación: convención de llamada , algoritmo de alteración de nombres (decoración de nombres), etc.

Solo dos vinculaciones de lenguaje están garantizadas de ser compatibles:

  1. "C++" , el enlace de lenguaje predeterminado.
  2. "C" , que permite enlazar con funciones escritas en el lenguaje de programación C, y definir, en un programa C++, funciones que pueden ser llamadas desde unidades escritas en C.
extern "C"
{
    int open(const char *path_name, int flags); // declaración de función C
}
int main()
{
    int fd = open("test.txt", 0); // llama a una función C desde un programa C++
}
// Esta función C++ puede ser llamada desde código C
extern "C" void handler(int)
{
    std::cout << "Callback invoked\n"; // Puede usar C++
}

Dado que el enlace de lenguaje es parte de cada tipo de función, los punteros a funciones también mantienen el enlace de lenguaje. El enlace de lenguaje de los tipos de función (que representa la convención de llamada) y el enlace de lenguaje de los nombres de función (que representa el name mangling) son independientes entre sí:

extern "C" void f1(void(*pf)()); // declara una función f1 con vinculación C,
                             // que retorna void y toma un puntero a una función C
                             // que retorna void y no toma parámetros
extern "C" typedef void FUNC(); // declara FUNC como un tipo de función C que retorna void
                                // y no toma parámetros
FUNC f2;            // el nombre f2 tiene vinculación C++, pero su tipo es función C
extern "C" FUNC f3; // el nombre f3 tiene vinculación C y su tipo es función C void()
void (*pf2)(FUNC*); // el nombre pf2 tiene vinculación C++, y su tipo es
                    // "puntero a una función C++ que retorna void y toma un
                    // argumento de tipo 'puntero a la función C que retorna void
                    // y no toma parámetros'"
extern "C"
{
    static void f4(); // el nombre de la función f4 tiene vinculación interna (sin lenguaje)
                      // pero el tipo de la función tiene vinculación de lenguaje C
}

Si dos declaraciones de una entidad le asignan diferentes vinculaciones de lenguaje, el programa está mal formado; no se requiere diagnóstico si ninguna declaración es accesible desde la otra. Una redeclaración de una entidad sin una especificación de vinculación hereda la vinculación de lenguaje de la entidad y su tipo (si existe).

extern "C" int f();
extern "C++" int f(); // Error: enlaces de lenguaje diferentes
extern "C" int g();
int g(); // OK, tiene enlace de lenguaje C
int h(); // tiene enlace de lenguaje C++ por defecto
extern "C" int h(); // Error: enlaces de lenguaje diferentes

Reglas especiales para enlace "C"

Cuando los miembros de clase , las funciones friend con una cláusula requires final , (desde C++20) o las funciones miembro no estáticas aparecen en un bloque de lenguaje "C" , la vinculación de sus tipos permanece "C++" (pero los tipos de parámetros, si los hay, permanecen "C" ):

extern "C"
{
    class X
    {
        void mf();           // la función mf y su tipo tienen vinculación de lenguaje C++
        void mf2(void(*)()); // la función mf2 tiene vinculación de lenguaje C++;
                             // el parámetro tiene tipo "puntero a función C"
    };
}
template<typename T>
struct A { struct B; };
extern "C"
{
    template<typename T>
    struct A<T>::B
    {
        friend void f(B*) requires true {} // vinculación de lenguaje C ignorada
    };
}
namespace Q
{
    extern "C" void f(); // no está mal formado
}

Sea C una declaración que declara una función o variable con vinculación de lenguaje "C" . Si otra declaración D declara una entidad con el mismo nombre, y satisface cualquiera de las siguientes condiciones, C y D declaran la misma entidad:

  • D declara una variable que pertenece al ámbito global.
  • Si C declara una variable, D también declara una variable.
  • Si C declara una función, D también declara una función.

A diferencia de las redeclaraciones regulares , C y D pueden tener diferentes ámbitos de destino :

extern "C"
{
    int x;
    int f();
    int g() { return 1; }
}
namespace A
{
    int x;                // Error: redefine «x»
    int f();              // OK, redeclara «f»
    int g() { return 1; } // Error: redefine «g»
}

Sin embargo, las restricciones de tales declaraciones aún se aplican, lo que significa que ambas deben declarar funciones o ambas deben declarar variables, y las entidades declaradas deben tener el mismo tipo:

namespace A
{
    extern "C" int x();
    extern "C" int y();
}
int x; // Error: redeclara "x" como un tipo de entidad diferente
namespace B
{
    void y(); // Error: redeclara "y" con un tipo diferente
}

Notas

Las especificaciones de lenguaje solo pueden aparecer en el ámbito de espacio de nombres .

Las llaves de la especificación del lenguaje no establecen un ámbito.

Cuando las especificaciones de lenguaje se anidan, la especificación más interna es la que está en vigor.

Una declaración contenida directamente en una especificación de vinculación de lenguaje se trata como si contuviera el extern especificador para el propósito de determinar la vinculación del nombre declarado y si es una definición .

extern "C" int x; // una declaración y no una definición
// La línea anterior es equivalente a extern "C" { extern int x; }
extern "C" { int x; } // una declaración y definición
extern "C" double f();
static double f(); // error: conflicto de vinculación
extern "C" static void g(); // error: conflicto de vinculación

extern "C" permite incluir archivos de cabecera que contienen declaraciones de funciones de biblioteca C en un programa C++, pero si el mismo archivo de cabecera se comparte con un programa C, extern "C" (que no está permitido en C) debe ocultarse con un #ifdef apropiado, típicamente __cplusplus :

#ifdef __cplusplus
extern "C" int foo(int, int); // El compilador C++ ve esto
#else
int foo(int, int);            // El compilador C ve esto
#endif

El único compilador moderno que diferencia tipos de función con "C" y "C++" enlaces de lenguaje es Oracle Studio; otros no permiten sobrecargas que solo difieran en el enlace de lenguaje, incluyendo los conjuntos de sobrecarga requeridos por el estándar de C++ ( std::qsort , std::bsearch , std::signal , std::atexit , y std::at_quick_exit ): GCC bug 2316 , Clang bug 6277 , CWG issue 1555 .

extern "C"   using c_predfun   = int(const void*, const void*);
extern "C++" using cpp_predfun = int(const void*, const void*);
// mal formado, pero aceptado por la mayoría de los compiladores
static_assert(std::is_same<c_predfun, cpp_predfun>::value,
              "Los enlaces de lenguaje C y C++ no deben diferenciar tipos de función.");
// las siguientes declaraciones no declaran sobrecargas en la mayoría de los compiladores
// porque c_predfun y cpp_predfun se consideran del mismo tipo
void qsort(void* base, std::size_t nmemb, std::size_t size, c_predfun*   compar);
void qsort(void* base, std::size_t nmemb, std::size_t size, cpp_predfun* compar);

Palabras clave

extern

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 4 C++98 los nombres con enlace interno pueden tener enlaces de lenguaje limitado a nombres con enlace externo
CWG 341 C++98 una función con enlace de lenguaje "C" puede
tener el mismo nombre que una variable global
el programa está mal formado en este caso
(no se requiere diagnóstico si aparecen
en diferentes unidades de traducción)
CWG 564 C++98 el programa estaba mal formado si dos declaraciones
solo diferían en las especificaciones de enlace de lenguaje
(es decir, diferentes literales de cadena después de 'extern')
se comparan los enlaces de lenguaje reales dados
por las declaraciones en su lugar
CWG 2460 C++20 las funciones friend con una cláusula requires final
y enlace de lenguaje "C" tenían comportamientos conflictivos
el enlace de lenguaje "C"
se ignora en este caso
CWG 2483 C++98 el enlace de los tipos de funciones miembro estáticas
que aparecen en bloques de lenguaje "C" era "C++"
el enlace es "C"

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 9.11 Especificaciones de vinculación [dcl.link]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 9.11 Especificaciones de vinculación [dcl.link]
  • Estándar C++17 (ISO/IEC 14882:2017):
  • 10.5 Especificaciones de vinculación [dcl.link]
  • Estándar C++14 (ISO/IEC 14882:2014):
  • 7.5 Especificaciones de vinculación [dcl.link]
  • Estándar C++11 (ISO/IEC 14882:2011):
  • 7.5 Especificaciones de vinculación [dcl.link]
  • Estándar C++03 (ISO/IEC 14882:2003):
  • 7.5 Especificaciones de vinculación [dcl.link]
  • Estándar C++98 (ISO/IEC 14882:1998):
  • 7.5 Especificaciones de vinculación [dcl.link]