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"
.