J'ai une fonction C que je voudrais appeler à partir de C ++. Je n'ai pas pu utiliser le extern "C" void foo()
type d'approche " " car la fonction C n'a pas pu être compilée avec g ++. Mais il se compile bien en utilisant gcc. Des idées comment appeler la fonction à partir de C ++?
90
g++
des messages d'erreurvoid valid_in_C_but_not_in_CPlusPlus(size_t size) { char variable_length_array[size]; }
void f(void *pv) { int *pi = pv; *pi = 42; }
^^Réponses:
Compilez le code C comme ceci:
gcc -c -o somecode.o somecode.c
Ensuite, le code C ++ comme ceci:
g++ -c -o othercode.o othercode.cpp
Puis liez-les ensemble, avec l'éditeur de liens C ++:
g++ -o yourprogram somecode.o othercode.o
Vous devez également indiquer au compilateur C ++ qu'un en-tête C arrive lorsque vous incluez la déclaration pour la fonction C. Alors
othercode.cpp
commence par:extern "C" { #include "somecode.h" }
somecode.h
devrait contenir quelque chose comme:#ifndef SOMECODE_H_ #define SOMECODE_H_ void foo(); #endif
(J'ai utilisé gcc dans cet exemple, mais le principe est le même pour n'importe quel compilateur. Construisez séparément en C et C ++, respectivement, puis liez-le ensemble.)
la source
extern "C"
dans l'en-tête avec#ifdef __cplusplus
.Permettez-moi de rassembler les éléments des autres réponses et commentaires, pour vous donner un exemple avec du code C et C ++ clairement séparés:
La partie C:
toto.h :
#ifndef FOO_H #define FOO_H void foo(void); #endif
toto.c
#include "foo.h" void foo(void) { /* ... */ }
Compilez-le avec
gcc -c -o foo.o foo.c
.La partie C ++:
bar.cpp
extern "C" { #include "foo.h" //a C header, so wrap it in extern "C" } void bar() { foo(); }
Compilez ceci avec
g++ -c -o bar.o bar.cpp
Et puis liez le tout ensemble:
g++ -o myfoobar foo.o bar.o
Raison d'être: Le code C devrait être du code C brut, pas de
#ifdef
s pour "peut-être qu'un jour j'appellerai cela d'une autre langue". Si un programmeur C ++ appelle vos fonctions C, c'est leur problème de faire cela, pas le vôtre. Et si vous êtes le programmeur C ++, alors l'en-tête C n'est peut-être pas le vôtre et vous ne devriez pas le changer, donc la gestion des noms de fonctions démêlés (c'est-à-dire leextern "C"
) appartient à votre code C ++.Vous pouvez, bien sûr, vous écrire un en-tête C ++ pratique qui ne fait rien sauf envelopper l'en-tête C dans une
extern "C"
déclaration.la source
Je suis d'accord avec la réponse du professeur Falken , mais après le commentaire d'Arne Mertz, je veux donner un exemple complet (la partie la plus importante est 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 // ... }
Ensuite, vous suivez les instructions du professeur Falken pour compiler et lier.
Cela fonctionne car lors de la compilation avec
gcc
, la macro__cplusplus
n'est pas définie, donc l'en-têtesomecode.h
inclus danssomecode.c
est comme ceci après le prétraitement:void foo(void);
et lors de la compilation avec
g++
, alors__cplusplus
est défini, et donc l'en-tête inclus dansothercode.cpp
est maintenant comme ça:extern "C" { void foo(void); }
la source
#ifdef __cplusplus
code en C. Le code C est le niveau inférieur, et il ne devrait pas avoir à s'inquiéter s'il peut être appelé à partir du code C ++ un jour. Imo qui#ifdef
n'a son utilisation que dans le code C ++ si vous souhaitez fournir un en-tête de liaison C pour une bibliothèque écrite en C ++, et non l'inverse.Cette réponse est inspirée d'un cas où la justification d'Arne était correcte. Un fournisseur a écrit une bibliothèque qui supportait autrefois à la fois C et C ++; cependant, la dernière version ne supportait que C. Les directives restantes suivantes laissées dans le code étaient trompeuses:
#ifdef __cplusplus extern "C" { #endif
Cela m'a coûté plusieurs heures à essayer de compiler en C ++. Appeler simplement C à partir de C ++ était beaucoup plus facile.
La convention ifdef __cplusplus est en violation du principe de responsabilité unique. Un code utilisant cette convention essaie de faire deux choses à la fois:
C'est comme essayer d'écrire en anglais américain et britannique en même temps. Cela lance inutilement une clé #ifdef __thequeensenglish #elif __yankeeenglish #else un outil inutile qui rend le code plus difficile à lire #endif dans le code.
Pour le code simple et les petites bibliothèques, la convention ifdef __cplusplus peut fonctionner; cependant, pour les bibliothèques complexes, il est préférable de choisir l'une ou l'autre langue et de s'y tenir. La prise en charge de l'une des langues demandera moins de maintenance que la prise en charge des deux.
Ceci est un enregistrement des modifications que j'ai apportées au code d'Arne pour le faire compiler sur Ubuntu Linux.
toto.h :
#ifndef FOO_H #define FOO_H void foo(void); #endif
toto.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
la source