una todas tipos llamar lenguaje las funciones funcion ejemplos como c++ c linux extern-c

c++ - todas - tipos de funciones en lenguaje c



Llamar a una función C desde el código C++ (4)

Tengo una función C a la que me gustaría llamar desde C ++. No pude usar el tipo de aproximación " extern "C" void foo() " porque no se compiló la función C usando g ++. Pero compila bien usando gcc. ¿Alguna idea de cómo llamar a la función desde C ++?


Compila el código C de esta manera:

gcc -c -o somecode.o somecode.c

Entonces el código de C ++ así:

g++ -c -o othercode.o othercode.cpp

Luego, únelos con el enlazador C ++:

g++ -o yourprogram somecode.o othercode.o

También debe decirle al compilador C ++ que se acerca un encabezado C cuando incluye la declaración para la función C. Entonces othercode.cpp comienza con:

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

somecode.h debe contener algo como:

#ifndef SOMECODE_H_ #define SOMECODE_H_ void foo(); #endif (Utilicé gcc en este ejemplo, pero el principio es el mismo para cualquier compilador. Construya por separado como C y C ++, respectivamente, luego vincule todo).


Esta respuesta está inspirada en un caso en el que la lógica de Arne era correcta. Un vendedor escribió una biblioteca que una vez admitió C y C ++; sin embargo, la última versión solo es compatible con C. Las siguientes directivas vestigiales que quedaron en el código fueron engañosas:

#ifdef __cplusplus extern "C" { #endif

Esto me costó varias horas intentar compilar en C ++. Simplemente llamar a C desde C ++ fue mucho más fácil.

La convención ifdef __cplusplus infringe el principio de responsabilidad única. Un código que usa esta convención trata de hacer dos cosas a la vez:

  • (1) ejecuta una función en C - y -
  • (2) ejecuta la misma función en C ++

Es como tratar de escribir en inglés americano y británico al mismo tiempo. Esto innecesariamente arroja un #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else una herramienta inútil que hace que el código sea más difícil de leer #endif en el código.

Para código simple y bibliotecas pequeñas, la convención ifdef __cplusplus puede funcionar; sin embargo, para bibliotecas complejas, lo mejor es seleccionar un idioma u otro y seguir con él. El soporte de uno de los idiomas requerirá menos mantenimiento que tratar de admitir ambos.

Este es un registro de las modificaciones que hice al código de Arne para que compilara en Ubuntu Linux.

foo.h :

#ifndef FOO_H #define FOO_H void foo(void); #endif

foo.c

#include "foo.h" #include <stdio.h> void foo(void) { // modified to verify the code was called printf("This Hello World was called in C++ and written in C/n"); }

bar.cpp

extern "C" { #include "foo.h" //a C header, so wrap it in extern "C" } int main() { foo(); return(0); }

Makefile

# -*- MakeFile -*- # dont forget to use tabs, not spaces for indents # to use simple copy this file in the same directory and type ''make'' myfoobar: bar.o foo.o g++ -o myfoobar foo.o bar.o bar.o: bar.cpp g++ -c -o bar.o bar.cpp foo.o: foo.c gcc -c -o foo.o foo.c


Estoy de acuerdo con la respuesta del profesor Falken , pero después del comentario de Arne Mertz quiero dar un ejemplo completo (la parte más importante es #ifdef __cplusplus ):

somecode.h

#ifndef H_SOMECODE #define H_SOMECODE #ifdef __cplusplus extern "C" { #endif void foo(void); #ifdef __cplusplus } #endif #endif /* H_SOMECODE */

somecode.c

#include "somecode.h" void foo(void) { /* ... */ }

othercode.hpp

#ifndef HPP_OTHERCODE #define HPP_OTHERCODE void bar(); #endif /* HPP_OTHERCODE */

othercode.cpp

#include "othercode.hpp" #include "somecode.h" void bar() { foo(); // call C function // ... }

Luego sigue las instrucciones del Prof. Falken para compilar y vincular.

Esto funciona porque al compilar con gcc , la macro __cplusplus no está definida, por lo que el encabezado somecode.h incluido en somecode.c es así después del preprocesamiento:

void foo(void);

y al compilar con g++ , entonces __cplusplus está definido, y entonces el encabezado incluido en othercode.cpp ahora es así:

extern "C" { void foo(void); }


Permítanme recopilar los retazos de las otras respuestas y comentarios, para darles un ejemplo con códigos C y C ++ claramente separados:

La parte C:

foo.h :

#ifndef FOO_H #define FOO_H void foo(void); #endif

foo.c

#include "foo.h" void foo(void) { /* ... */ }

Compila esto con gcc -c -o foo.o foo.c

La parte de C ++:

bar.cpp

extern "C" { #include "foo.h" //a C header, so wrap it in extern "C" } void bar() { foo(); }

Compila esto con g++ -c -o bar.o bar.cpp

Y luego vincular todo junto:

g++ -o myfoobar foo.o bar.o

Justificación: El código C debe ser código C simple, no #ifdef s para "tal vez algún día lo llame desde otro idioma". Si algún programador de C ++ llama a tus funciones C, es su problema cómo hacerlo, no el tuyo. Y si usted es el programador de C ++, entonces el encabezado C podría no ser suyo y no debería cambiarlo, por lo que el manejo de nombres de funciones no registradas (es decir, el extern "C" ) pertenece a su código C ++.

Por supuesto, puede escribir usted mismo un encabezado C ++ de conveniencia que no hace más que ajustar el encabezado C en una declaración extern "C" .