Tengo una función en C que me gustaría llamar desde C ++. " extern "C" void foo()
" No pude usar el tipo de enfoque porque la función C no pudo compilarse usando g ++. Pero se compila bien usando gcc. ¿Alguna idea de cómo llamar a la función desde C ++?
90
g++
mensajes de error?void valid_in_C_but_not_in_CPlusPlus(size_t size) { char variable_length_array[size]; }
void f(void *pv) { int *pi = pv; *pi = 42; }
^^Respuestas:
Compile el código C así:
gcc -c -o somecode.o somecode.c
Entonces el código C ++ como este:
g++ -c -o othercode.o othercode.cpp
Luego, vincúlelos con el vinculador de C ++:
g++ -o yourprogram somecode.o othercode.o
También tiene que decirle al compilador de C ++ que viene un encabezado de C cuando incluye la declaración para la función de 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
(Usé gcc en este ejemplo, pero el principio es el mismo para cualquier compilador. Compile por separado como C y C ++, respectivamente, luego vincúlelo).
fuente
extern "C"
el encabezado con#ifdef __cplusplus
.Permítame recopilar los fragmentos de las otras respuestas y comentarios, para darle un ejemplo con código C y C ++ claramente separado:
La parte C:
foo.h :
#ifndef FOO_H #define FOO_H void foo(void); #endif
foo.c
#include "foo.h" void foo(void) { /* ... */ }
Compile 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 vincularlo 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 "quizás algún día llamaré a esto desde otro idioma". Si algún programador de C ++ llama a sus funciones de C, es su problema cómo hacerlo, no el suyo. Y si usted es el programador de C ++, entonces el encabezado de C podría no ser suyo y no debería cambiarlo, por lo que el manejo de los nombres de funciones sin alterar (es decir, elextern "C"
) pertenece a su código de C ++.Por supuesto, puede escribir usted mismo un encabezado C ++ conveniente que no haga nada más que envolver el encabezado C en una
extern "C"
declaración.fuente
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 la
#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 siga 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 encabezadosomecode.h
incluido ensomecode.c
es así después del preprocesamiento:void foo(void);
y cuando se compila con
g++
, entonces__cplusplus
se define, por lo que el encabezado incluido enothercode.cpp
ahora es así:extern "C" { void foo(void); }
fuente
#ifdef __cplusplus
código en C. El código C es el nivel más bajo, y no debería tener que preocuparse si algún día podría ser llamado desde el código C ++. Imo que#ifdef
tiene su uso solo en código C ++ si desea proporcionar un encabezado de enlace C para una biblioteca escrita en C ++, y no al revés.Esta respuesta está inspirada en un caso en el que el razonamiento de Arne era correcto. Un proveedor escribió una biblioteca que una vez admitió tanto C como C ++; sin embargo, la última versión solo admite C. Las siguientes directivas vestigiales que quedan en el código eran 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 viola el principio de responsabilidad única. Un código que utiliza esta convención intenta hacer dos cosas a la vez:
Es como intentar escribir en inglés americano y británico al mismo tiempo. Esto es innecesariamente lanzar 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 es mejor elegir un idioma u otro y seguir con él. Admitir uno de los idiomas requerirá menos mantenimiento que intentar admitir ambos.
Este es un registro de las modificaciones que hice al código de Arne para que se 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
fuente