2011-11-03 21 views
5

Sé cómo usar extern "C" pero, ¿cuáles son las condiciones cuando debe usarlo?Cuándo usar extern "C"?

extern "C" dice compilador de C++ no llevar a cabo cualquier nombre-mangling en el código dentro de las llaves. Esto le permite llamar a las funciones C desde dentro de C++.

Por ejemplo:

#include <string.h> 

int main() 
{ 
    char s[] = "Hello"; 
    char d[6]; 

    strcpy_s(d, s); 
} 

Si bien esto compila bien en VC++. Pero a veces esto se escribe como:

extern "C" { 
#include <string.h> 
} 

No veo el punto. ¿Puedes dar un ejemplo real en el que sea necesario extern "C"?

+7

En lugar de piratería '' para evitar renombrado de nombres, el uso el encabezado ''. –

+0

@AlexandreC .: no es una buena idea usar los encabezados ''. Un encabezado '' * no * garantiza colocar identificadores en el espacio de nombres global, rompiendo así el código que se basa en identificadores de espacio de nombres globales cuando ese código se mueve a otro compilador. Además, un encabezado '' puede y en la práctica colocará identificadores en el espacio de nombres global, por lo tanto, en teoría también se rompe el código que se basa en un espacio de nombres global no contaminado. "En teoría" es demasiado vago; al menos un idiota hizo eso. Entonces, no los uses. –

+0

@ AlfP.Steinbach: Si escribe C++, use ''. Si escribe C, use '' y ** compile su código con un compilador de C **.Mezclar idiomas es * no * una buena idea. –

Respuesta

4

Un uso muy común de extern "C" cuando está exportando una función de una biblioteca. Si no desactiva la creación de nombres de C++, de lo contrario puede hacer que sea muy difícil para los clientes de su biblioteca nombrar su función. Y del mismo modo, cuando va en la otra dirección, cuando está importando una función que ha sido exportada con un enlace C.

6

Utiliza extern "C" para evitar el cambio de nombres dentro de los archivos de encabezado y sus archivos de objetos C++ para bibliotecas u objetos que ya se han compilado sin modificarlos.

Por ejemplo, supongamos que tiene una biblioteca widget que se compiló con un compilador de C para que su interfaz publicada no se destruya.

Si incluye el archivo de encabezado tal como está en su código, asumirá que los nombres son mutilados y esas versiones destruidas son lo que le dirá al vinculador que busque.

Sin embargo, como solicitará algo como [email protected]_float_charptr y la biblioteca widget solo habrá publicado function, se encontrará con problemas.

Sin embargo, si se incluyen con:

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

su compilador sabrá que debería tratar de utilizar function, la versión no mutilada.

Por eso, en los archivos de cabecera para cosas C destinados a ser incluidos en los programas de C _or C++, verá cosas como:

#ifdef __cplusplus 
    extern "C" { 
#endif 

// Everything here works for both C and C++ compilers. 

#ifdef __cplusplus 
    } 
#endif 

Si utiliza un compilador de C para incluir esto, los #ifdef líneas hará que las cosas extern "C" desaparezcan. Para un compilador de C++ (donde se define __cplusplus), todo será sin triturar.

+0

¿por qué hay un segundo '#ifdef __cplusplus' para? – user103214

+0

@ user974191: es para la abrazadera de cierre, de lo contrario, las abrazaderas estarían desequilibradas. – paxdiablo

1

Cuando establece un enlace con las bibliotecas que están escritas en C extern le dice al compilador que no decore los nombres para que el enlazador pueda encontrar las funciones. En C++, los nombres de funciones y otros tienen información para el enlazador, p. tipos y tamaños de argumentos contenidos en el nombre.

1

Si está produciendo una biblioteca binaria A que expone una función a la que le gustaría llamar desde el binario B.

Imagine A es A.dll y B es B.exe y usted está en un sistema Windows.

C++ no describe un diseño binario tal que B sabe cómo llamar a A. Normalmente, este problema se soluciona utilizando el mismo compilador para producir A y B. Si desea una solución más genérica, utilice la palabra clave extern. Esto expone la función de una manera C. C describe un formato binario para que diferentes binarios de diferentes compiladores puedan comunicarse entre sí.

Ver: http://en.wikipedia.org/wiki/Application_binary_interface http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B

1

Si, dentro de su código C++, que #include una cabecera para una biblioteca externa (codificado en C) y si las funciones que hay no declaró extern "C" que no trabajarán (se Obtendrá referencia indefinida en el momento del enlace).

Pero en estos días, la gente de codificación de bibliotecas de C y la prestación de los archivos de cabecera para que tienden a saber que, a menudo, poner el extern "C" en su archivo de cabecera (adecuadamente protegido con #ifdef __cplusplus)

Tal vez una mejor manera de entender es utilice (suponiendo que tenga un sistema Linux) la utilidad nm para mostrarle los nombres (no marcados) utilizados en una biblioteca o un ejecutable.

3

Aquí hay un ejemplo concreto de dónde las cosas se rompen y necesita extern "C" para arreglarse.

module.h:

int f(int arg); 

module.c:

int f(int arg) { 
    return arg + 1; 
} 

main.cpp:

#include "module.h" 

int main() { 
    f(42); 
} 

Dado que estoy mezclando C y C++, esto no se vinculará (de los dos archivos de objeto, solo uno sabrá f bajo su nombre deformado en C++).

Tal vez la forma más limpia para solucionar este problema es haciendo que el archivo de cabecera compatible tanto con C y C++:

module.h:

#ifdef __cplusplus 
    extern "C" { 
#endif 

int f(int arg); 

#ifdef __cplusplus 
    } 
#endif 
+0

+1 esto explica lo que estaba buscando. – user103214