Executer du code C++ dans du code C

Problème:
Vous voulez vous simplifier la vie en codant en C++ mais le reste de votre équipe est composé de vieux gnous qui ne veulent pas se mettre a l'orienté objet?
(ok il existe des bibliothèque pour faire de l'orienté objet en C mais soyons réaliste,
on atteins rapidement les limites du langage)
Le C++ se traduit en C, il n'apporte donc rien de nouveau
Et bien oui et non, en effet on pourrait s'amuser (d’ailleurs les plus vieux des gnous ne font que ça)
à réécrire tout son code C++ en C et avaler 3 boîtes d'aspirine pour convertir son code mais il y a plus simple.
g++ (ainsi que n'importe quel autre compilateur c++) peuvent compiler du code C,
c'est cette fonctionnalité que nous utiliserons pour exécuter notre code C++.
Du code C dans du C++?
Je vous vois venir, c'est un tuto pour faire exactement l'inverse de ce que je dis, mais pas de panique, on y viens
Pour exécuter son code cpp dans son code c, un seul mot d'ordre "encapsulation".
Votre compilateur C ne peut compiler que du code C, nous allons donc lui fournir.
Pensez aux nombreuses bibliothèques que vous avez inclues dans vos projet, au final vous n'aviez qu'un fichier compilé
(.so) et un header (.h) et au final (a part pour les plus barbus d'entre nous) vous ne saviez pas ce qu'il y avait dans votre bibliothèque, peut être même que du code C++ s'y cachait sans le savoir
Du code!
notre fichier cpp:
void Miaou::miauler(){ std::cout << "miaou!" << std::endl; }
le fichier c que l'on souhaiterais obtenir:
#include "parser.h" int main(){ miauler(); /* il manque quelque chose mais c'est pour donner une idée de ce que l'on cherche à obtenir */ return 0; }
Manque plus que le fichier qui fait la liaison des deux code que j'ai nommé ici parser.
Parser
Le parser doit permettre l’exécution du code cpp a partir de celui écrit en C,
en c++, plus haut je parlais d'encapsulation, c'est ce que nous allons faire ici,
pour chaque méthode publique de notre fichier cpp, nous lui créerons une fonction C
qui ne fera qu'appeler cette méthode.
Parser.cpp
#include "Miaou.hpp" Miaou* createNewMiaou(){ return new Miaou(); } void destructMiaou(Miaou* chat){ delete chat; } void miauler(Miaou* chat){ //c'est ce qu'il manquait, on applique une méthode sur un objet chat->miauler(); }
voila, rien de bien compliquer une fois compilé, nous obtenons un code C qui ne pose aucun problème de link pour gcc
(enfin, pratiquement...)
il manque en effet la touche finale, le "name mangling" (le compilateur renomme toute les fonctions parce qu'il aime pas les chats)
est différent pour le compilateur C++ et C, il suffit juste de lui préciser d'utiliser le même nom pour ne pas qu'il se perde une fois rendu au linkage.
Parser.hpp:
#include "Miaou.hpp" extern "C"{ //utiliser les convention du C, Miaou* createNewMiaou(); void destructMiaou(Miaou* chat); void miauler(Miaou* chat); }
eh mais, on utilise des pointeur de Miaou, mais gcc ne connait pas les objets!
effectivement mais ce ne sont pas des objet mais des pointeurs d'objet, on utilisera donc un type générique, le void*
qui sera de toute façon transtypé correctement dans notre code cpp.
Parser.h
typedef void* Miaou; Miaou* createNewMiaou(); void destructMiaou(Miaou* chat); void miauler(Miaou* chat);
il ne manque plus qu'a compiler notre library:
[quote]
g++ -fPIC -shared *.cpp -o libMiaou.so
[/quote]
Memo
- Créer un parser qui encapsule les méthodes publique d'une classe
#include "ClassCpp.hpp" ClasseCpp* createObjet(){ return new ClasseCpp(); } void executeMethodeMiaou(ClasseCpp *objet){ objet->methodeMiaou(); } int executeMethodeChat(ClasseCpp *objet, int milk){ objet->methodeChat(milk); }
- Créer un fichier hpp pour spécifier un name Mangling de type C
extern "C"{ ClasseCpp* createObjet() void executeMethodeMiaou(ClasseCpp *objet); int executeMethodeChat(ClasseCpp *objet, int milk); }
- header de notre library utilisant des void*
typedef void * MD25Command; ClasseCpp* createObjet() void executeMethodeMiaou(ClasseCpp *objet); int executeMethodeChat(ClasseCpp *objet, int milk);
Notes
En vrac,
Si vous créez une library, penser à la passer en LGPL ; )
Les compilateurs n'utilisent pas forcement un name mangling identique par langage (vous devrez sans doute utiliser un compilateur C de la même "marque" que votre compilateur C++)
C'est tordu? on me le dit souvent...
si vous avez d'autres remarques, n’hésitez pas a laisser un commentaire ; )
PS: (si quelqu'un passe par là et trouve que j'ai fait trop de faute de grammaire/orthographe/syntaxe (malheureusement pas de mention inutile...) je le remercie d'avance de ne pas pouvoir lire ce document sans pouvoir s’empêcher de le corriger :- ° )