from example ejemplo c++ c extern-c

c++ - example - ¿Cómo funciona una declaración externa "C"?



extern function c (9)

Aquí hay una cita de msdn

"La palabra clave extern declara una variable o función y especifica que tiene una vinculación externa (su nombre es visible desde los archivos distintos de aquel en el que está definida). Al modificar una variable, extern especifica que la variable tiene una duración estática (se asigna cuando el programa comienza y se desasigna cuando finaliza el programa). La variable o función puede definirse en otro archivo de origen, o más adelante en el mismo archivo. Las declaraciones de variables y funciones en el ámbito del archivo son externas de forma predeterminada ".

http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx

Estoy tomando un curso de lenguajes de programación y estamos hablando de la declaración extern "C" .

¿Cómo funciona esta declaración en un nivel más profundo que no sea el "interfaz C y C ++"? ¿Cómo afecta esto a los enlaces que tienen lugar en el programa también?


Cabe señalar que extern "C" también modifica los tipos de funciones. No solo modifica cosas en niveles inferiores:

extern "C" typedef void (*function_ptr_t)(); void foo(); int main() { function_ptr_t fptr = &foo; } // error!

El tipo de &foo no es igual al tipo que designa typedef (aunque el código es aceptado por algunos compiladores, pero no por todos).


Cuando marca un bloque de código con una "C" externa, le está diciendo al sistema que use un enlace de estilo C.

Esto, principalmente, afecta la forma en que el enlazador maneja los nombres. En lugar de utilizar la manipulación de nombres de estilo C ++ (que es más complejo para soportar sobrecargas de operadores), obtiene el nombre de estilo C estándar fuera del vinculador.


En C ++, el nombre / símbolo de las funciones en realidad se renombra a otra cosa tal que diferentes clases / espacios de nombres pueden tener funciones de las mismas firmas. En C, todas las funciones están definidas globalmente y no se necesita ningún proceso de cambio de nombre personalizado.

Para hacer que C ++ y C se hablen entre sí, "extern C" le indica al compilador que no use la convención de C.


Veamos una función típica que puede compilar tanto en C como en C ++:

int Add (int a, int b) { return a+b; }

Ahora en C la función se llama "_Add" internamente. Mientras que la función de C ++ se denomina algo completamente diferente internamente mediante un sistema llamado name-mangling. Es básicamente una forma de nombrar una función para que la misma función con diferentes parámetros tenga un nombre interno diferente.

Entonces, si Add () está definido en add.c, y tiene el prototipo en add.h, obtendrá un problema si intenta incluir add.h en un archivo C ++. Debido a que el código C ++ está buscando una función con un nombre diferente al de add.c, obtendrá un error de vinculador. Para solucionar ese problema, debe incluir add.c mediante este método:

extern "C" { #include "add.h" }

Ahora el código de C ++ se vinculará con _Add en lugar de la versión modificada del nombre de C ++.

Ese es uno de los usos de la expresión. En pocas palabras, si necesita compilar un código que sea estrictamente C en un programa C ++ (mediante una declaración de inclusión o algún otro medio), debe ajustarlo con una declaración externa "C" {...}.


extern "C" denota que el código adjunto utiliza la vinculación de estilo C y la manipulación de nombres. C ++ utiliza un formato más complejo de nombres. Aquí hay un ejemplo:

mangled

int example(int alpha, char beta);

en C: _example

en C ++: __Z7exampleic

Actualización: como GManNickG señala en los comentarios, el patrón de manipulación de nombres depende del compilador.


extern "C", es una palabra clave para declarar una función con enlaces C, ya que el compilador C y el compilador C ++ traducirán la fuente a una forma diferente en el archivo objeto:

Por ejemplo, un fragmento de código es el siguiente:

int _cdecl func1(void) {return 0} int _stdcall func2(int) {return 0} int _fastcall func3(void) {return 1}

Los compiladores de C de 32 bits traducirán el código en la forma siguiente:

_func1 _func2@4 @func3@4

en el cdecl, func1 se traducirá como '' _nombre ''

en el stdcall, func2 se traducirá como '' _name @ X ''

en el fastcall, func2 se traducirá como '' @ nombre @ X ''

'' X '' significa la cantidad de bytes de los parámetros en la lista de parámetros.

La convención de 64 bits en Windows no tiene un guión bajo.

En C ++, se introducen clases, plantillas, espacios de nombres y sobrecarga de operadores, ya que no se permiten dos funciones con el mismo nombre, el compilador de C ++ proporciona la información de tipo en el nombre del símbolo,

por ejemplo, un fragmento de código es el siguiente:

int func(void) {return 1;} int func(int) {return 0;} int func_call(void) {int m=func(), n=func(0);}

El compilador de C ++ traducirá el código de la siguiente manera:

int func_v(void) {return 1;} int func_i(int) {return 0;} int func_call(void) {int m=_func_v(), n=_func_i(0);}

''_v'' y ''_i'' son información de tipo de ''void'' y ''int''


extern C afecta a la manipulación de nombres por el compilador de C ++. Es una forma de hacer que el compilador de C ++ no destruya los nombres, o más bien los destruya de la misma manera que lo haría un compilador de C. Esta es la forma en que se interconecta C y C ++.

Como ejemplo:

extern "C" void foo(int i);

permitirá que la función se implemente en un módulo C, pero permitirá que se llame desde un módulo C ++.

El problema se produce cuando se intenta obtener un módulo de C para llamar a una función de C ++ (obviamente C no puede usar clases de C ++) definido en un módulo de C ++. El compilador de C no le gusta extern "C" .

Así que necesitas usar esto:

#ifdef __cplusplus extern "C" { #endif void foo(int i); #ifdef __cplusplus } #endif

Ahora, cuando esto aparece en un archivo de encabezado, tanto los compiladores C como C ++ estarán satisfechos con la declaración y ahora podrían definirse en un módulo C o C ++, y pueden llamarse con código C y C ++.


extern "C" se utiliza para garantizar que los siguientes símbolos no estén mangled (decorados).

Ejemplo:

Digamos que tenemos el siguiente código en un archivo llamado test.cpp :

extern "C" { int foo() { return 1; } } int bar() { return 1; }

Si ejecuta gcc -c test.cpp -o test.o

Eche un vistazo a los nombres de los símbolos:

00000010 T _Z3barv

00000000 T foo

foo() mantiene su nombre.