J'ai une fonction C que je voudrais appeler à partir de C++. Je ne pouvais pas utiliser l'approche "extern "C" void foo()
" parce que la fonction C n'a pas été compilée avec g ++. Mais cela compile bien avec gcc. Des idées comment appeler la fonction de C++?
Me laisser rassembler les morceaux des autres réponses et commentaires, pour vous donner un exemple avec le code C et C++ clairement séparé:
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
.
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 reliez le tout ensemble:
g++ -o myfoobar foo.o bar.o
Justification: Le code C doit être un code C en clair, pas de #ifdef
s for "peut-être qu'un jour j'appellerai cela d'une autre langue". Si certains programmeurs C++ appellent vos fonctions C, c'est leur problème comment faire cela, pas le vôtre. Et si vous êtes programmeur C++, alors l’en-tête C pourrait ne pas vous appartenir et vous ne devriez pas le changer. Le traitement des noms de fonction non modifiés (c.-à-d. Le extern "C"
) appartient à votre code C++.
Vous pouvez bien sûr écrire vous-même un en-tête C++ pratique qui ne fait rien, si ce n’est envelopper l’en-tête C dans un fichier extern "C"
déclaration.
Je suis d'accord avec réponse du professeur Falken , mais après le commentaire d'Arne Mertz, je souhaite 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 car lors de la compilation avec gcc
, la macro __cplusplus
n'est pas défini, donc l'en-tête somecode.h
inclus dans somecode.c
est comme ça après le prétraitement:
void foo(void);
et lors de la compilation avec g++
, puis __cplusplus
is défini, et l’en-tête inclus dans othercode.cpp
est maintenant comme ça:
extern "C" {
void foo(void);
}
Cette réponse est inspirée par un cas où la justification d'Arne était correcte. Un fournisseur a écrit une bibliothèque qui supportait jadis les langages C et C++; cependant, la dernière version ne supportait que C. Les directives vestigiales suivantes laissées dans le code étaient trompeuses:
#ifdef __cplusplus
extern "C" {
#endif
Cela m'a coûté plusieurs heures d'essayer de compiler en C++. Il était beaucoup plus simple d'appeler C depuis C++.
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 jette inutilement une clé #ifdef __thequeensenglish #Elif __yankeeenglish # utilise 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'en tenir à celle-ci. La prise en charge d'une des langues nécessitera 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 le compiler sur 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