web-dev-qa-db-fra.com

Appeler une fonction C depuis le code C ++

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++?

79
Dangila

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é:

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 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 #ifdefs 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.

55
Arne Mertz

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);

}
16
gx_

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:

  • (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 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
0
Agriculturist