J'ai une fonction C que je voudrais appeler à partir de C++. Je ne peux pas utiliser " extern "C" void foo()
"parce que la fonction C n'a pas pu être compilée avec g++. Mais elle se compile bien avec gcc. Une idée pour appeler la fonction en C++ ?
Réponses
Trop de publicités?Compilez le code C comme ceci :
gcc -c -o somecode.o somecode.c
Puis le code C++ comme ceci :
g++ -c -o othercode.o othercode.cpp
Puis liez-les ensemble, avec le linker C++ :
g++ -o yourprogram somecode.o othercode.o
Vous devez également indiquer au compilateur C++ qu'un en-tête C est prévu lorsque vous incluez la déclaration de la fonction C. Ainsi, 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 tant que C et C++, respectivement, puis liez le tout ensemble).
Permettez-moi de rassembler les éléments des autres réponses et commentaires, afin de vous donner un exemple de code C et C++ proprement séparé :
La partie C :
foo.h :
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
void foo(void)
{
/* ... */
}
Compilez ceci 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 ensuite relier tout ça ensemble :
g++ -o myfoobar foo.o bar.o
Justification : Le code C doit être un simple code C, pas de #ifdef
pour "peut-être qu'un jour j'appellerai ceci depuis un autre langage". Si un programmeur C++ appelle vos fonctions C, c'est leur problème comment le faire, 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 modifier, donc la gestion des noms de fonctions non mélangés (c'est-à-dire l'en-tête extern "C"
) doit figurer dans votre code C++.
Vous pouvez, bien sûr, écrire vous-même un en-tête C++ de commodité qui ne fait rien d'autre que d'envelopper l'en-tête C dans un en-tête extern "C"
déclaration.
Je suis d'accord avec 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 le #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 parce que lorsque l'on compile avec gcc
la macro __cplusplus
n'est pas défini, donc l'en-tête somecode.h
inclus dans somecode.c
est comme ceci après le prétraitement :
void foo(void);
et lors de la compilation avec g++
entonces __cplusplus
est défini, et donc l'en-tête inclus dans othercode.cpp
est maintenant comme ça :
extern "C" {
void foo(void);
}
Cette réponse s'inspire d'un cas où le raisonnement d'Arne était correct. Un fournisseur a écrit une bibliothèque qui, à une époque, supportait à la fois le C et le C++ ; cependant, la dernière version ne supportait que le C. Les directives résiduelles 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 le C depuis le 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 :
- (1) exécuter une fonction en C -- et --
- (2) exécuter la même fonction en C++.
C'est comme essayer d'écrire en anglais américain et en anglais britannique en même temps. C'est jeter inutilement un #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #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 un langage ou l'autre et de s'y tenir. La prise en charge d'un des langages demandera moins de maintenance que d'essayer de prendre en charge les deux.
Ceci est un enregistrement des modifications que j'ai apportées au code d'Arne pour qu'il compile sous 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