|
UTILISATION DE SOURCES EN C++ DANS UN
PROGRAMME EN C
INTRODUCTION
Le présent document explique
comment utiliser des classes C++ dans un programme écrit en C et compilé avec
gcc sous Linux, Unix etc...
Le cas peut se présenter par
exemple lorsque des fonctionnalités ont été écrites en C++ dans le cadre d'un
autre projet et seraient réutilisable dans un nouveau projet écrit en C par une
tierce personne. plutôt que de réécrire entièrement l'une ou l'autre les
parties, il est possible de rassembler toutes les sources C++ dans une librairie
spécifique offrant une interface pour les sources de l'application écrite en C.
Nous allons dans un
premier temps créer un répertoire mylib et dans ce répertoire nous allons
créer deux fichiers simples que nous nommerons (par exemple) mylibtest.cpp
et mylibtest.h
mylibtest.cpp
contiendra le code suivant :
#include "mylibtest.h"
#include <iostream>
void
helloWorld()
{
std::cout << "hello" <<
std::endl;
et mylibtest.h
contiendra celui-ci :
#ifndef
MYLIBTEST_H
#define MYLIBTEST_H
void helloWorld();
#endif
donc le répertoire mylib contiendra :
mylibtest.cpp
mylibtest.h
Placons-nous dans le
répertoire mylib et compilons sans édition de liens (option –c)
le(s) fichier(s) de la librairie
g++ -c
mylibtest.cpp
ou bien
find
. –name "*.cpp" –exec g++ -c ‘{}’ \;
si plusieurs fichiers
.cpp sont à compiler.
Il doit y avoir
maintenant y avoir autant de fichiers objets (avec extension .o) que de fichier
.cpp et chacun d’eux doit porter le même nom que le fichier .cpp auquel il se
rapporte.
Dans notre exemple, le
répertoire mylib contiendra :
mylibtest.cpp
mylibtest.h
mylibtest.o
Dans un premier temps nous allons supprimer toute
éventuelle instance de cette librairie qui aurait été préalablement créée.
rm -f libtest.a
Puis nous allons concaténer les fichiers objets compilés
dans un seul fichier
ar cr libtest.a
fichier_obj1.o fichier_obj2.o etc…
dans notre exemple cela sera
ar cr libtest.a
mylibtest.o
Nous allons enfin finaliser (en liant entre eux les objets
de la librairie) avec la commande ranlib
/bin/ranlib
libtest.a
ou bien
/usr/bin/ranlib
libtest.a
suivant la location du fichier ranlib
A la fin de cette phase, le répertoire mylib doit
contenir :
mylibtest.cpp
mylibtest.h
mylibtest.o
libtest.a
le nom de notre librairie est
donc « test ». Dans le cas ou nous aurions choisi de créer avec la command ar un
fichier nommé libnomdemalibrairie.a, notre librairie s’appellerait
nomdemalibriaire (le préfixe lib et l’extension a sont
obligatoire)
Nous allons créer un fichier exec.cpp qui contiendra
le point d’entrée du programme hôte de la librairie.
Il contiendra donc :
#include
"mylibtest.h"
int main()
{
helloWorld();
return 1;
}
Nous le compileront avec la commande :
g++
exec.cpp –L. –ltest –o exec_cpp
Rq importante : les fichiers
utilisant qui en utilisent d’autres doivent etre liés spécifié (dans
l’ordre de liaison) avant les fichiers qu’ils utilisent ! Dans notre cas
nous devront donc spécifier le fichier exec.cpp (qui utilise la librairie) avant
la librairie elle-même.
L’option –L spécifie les chemins où se trouvent les
librairies à inclure.
L’option –l spécifie les librairies à utiliser, ici test,
puisque notre libriairie s’appelle libtest.a
Notre répertoire contiendra donc
mylibtest.cpp
mylibtest.h
mylibtest.o
exec.cpp
libtest.a
exec_cpp
le lancement du fichier exec_cpp doit nous afficher
« hello » sur l’écran
Afin qu’une fonction définie dans un fichier
C++ puisse être vue dans un programme compilé en C, il est nécessaire de la
déclarer à l’intérieur d’un bloc extern
"C" , en revanche, étant donné que ce bloc est défini dans le fichier
« .h », il sera utilisé aussi bien lors de la compilation de la librairie que de
la compilation du programme C, mais dans le cas de la librairie, la fonction ne
doit pas être déclarée dans un bloc extern, pour cela il convient d’utiliser une
directive pré-processeur qui inclura ou non un bloc extern suivant si le
compilateur a positionné la variable __cplusplus ou non.
Le fichier mylib.h devient donc
#ifndef
MYLIBTEST_H
#define MYLIBTEST_H
#ifdef
__cplusplus
extern "C"
{
#endif
void
helloWorld();
#ifdef
__cplusplus
}
#endif
#endif
/* MYLIBTEST_H */
Répéter les étapes des chapitres 2 et 3
Nous allons créer un fichier exec.c qui contiendra le point
d’entrée du programme hôte de la librairie.
Il contiendra donc :
#include
"mylibtest.h"
int main()
{
helloWorld();
return 1;
}
Nous le compileront avec la commande :
gcc
exec.c –L. –ltest –lstdc++ –o exec_c
Rq importante : les composants
utilisateurs (fichiers, librairies) doivent être spécifiés (dans l’ordre de
liaison) avant ceux dont ils ont besoin Dans notre cas nous devront donc
spécifier le fichier exec.c (qui utilise la librairie) avant la librairie
elle-même.
L’option –lstdc++, spécifie au
compilateur C qu’il devra devoir lier en plus la librairie standard du C++ (libstdc++.a),
puisque nous utilisons dans notre librairie des fonctionnalités de la STL
(Standard Type Library), dans notre cas, cette fonctionnalité est le
cout.
Remarque : si la librairie a
été compilée avec le mot clef –static, il ne devrait pas être nécessaire
de spécifier l’option –lstdc++, celle-ci devant alors se trouver directement
greffée dans la librairie que nous sommes en train de construire
Notre répertoire contiendra donc
mylibtest.cpp
mylibtest.h
mylibtest.o
exec.cpp
exec.c
libtest.a
exec_cpp
exec_c
Le lancement du fichier exec_c doit nous afficher « hello »
sur l’écran
Le langage C ne comprenant pas la notion de
classes, il est nécessaire d’encapsuler la création des classes et leur
utilisation dans autant de fonctions, et de créer des instances globales des
classes visibles depuis l’extérieures de la librairie.
Ainsi, si nous souhaitons créer
un classe HelloWorld charger d’afficher « Hello », nous devrons modifier les
fichiers de la façon suivante :
§
mylibtest.h
#ifndef
MYLIBTEST_H
#define
MYLIBTEST_H
#ifdef __cplusplus
class HelloWorld
{
public:
void
display();
};
extern "C"
{
#endif
void
HelloWorldInit();
void
HelloWorldDeinit();
void
HelloWorldDisplay();
#ifdef __cplusplus
}
#endif
#endif
§
mylibtest.cpp
#include
"mylibtest.h"
#include <iostream>
HelloWorld *
g_helloWorld;
void HelloWorld::display()
{
std::cout <<
"hello" << std::endl;
void
HelloWorldInit()
{
g_helloWorld = new HelloWorld;
}
void
HelloWorldDeinit()
{
if (g_helloWorld) delete g_helloWorld;
}
void
HelloWorldDisplay()
{
g_helloWorld->display();
}
§
exec.c
#include
"mylibtest.h"
int main()
{
HelloWorldInit();
HelloWorldDisplay();
HelloWorldDeinit();
return 1;
}
§
mylibtest.h
#ifndef
MYLIBTEST_H
#define
MYLIBTEST_H
#ifdef __cplusplus
class HelloWorld
{
public:
void
display();
};
extern "C"
{
#endif
void
HelloWorldInit();
void
HelloWorldDeinit();
void
HelloWorldCreate(int _num);
void
HelloWorldRelease(int _num);
void
HelloWorldDisplay(int _num);
#ifdef __cplusplus
}
#endif
#endif
§
mylibtest.cpp
#include
"mylibtest.h"
#include <iostream>
#include <map>
std::map<int, HelloWorld *,
std::less<int, HelloWorld *> > * g_helloWorlds;
void HelloWorld::display()
{
std::cout <<
"hello" << std::endl;
void
HelloWorldInit()
{
g_helloWorlds = new std::map<int, HelloWorld *, std::less<int, HelloWorld *> >;
}
void
HelloWorldDeinit()
{
if (g_helloWorlds) delete g_helloWorlds;
}
void
HelloWorldCreate(int _num)
{
if (!g_helloWorlds) return;
std::map<int, HelloWorld *,
std::less<int, HelloWorld *> >::iterator
p =
g_helloWorlds->find(_num);
if (p ==
datas.end())
g_helloWorlds->insert(std::pair<int, HelloWorld *>(_num,
new HelloWorld))
}
void
HelloWorldRelease(int _num)
{
if (!g_helloWorlds) return;
std::map<int, HelloWorld *,
std::less<int, HelloWorld *> >::iterator
p =
g_helloWorlds->find(_num);
if (p != datas.end())
delete
(*p).second;
}
void
HelloWorldDisplay(int
_num)
{
if (!g_helloWorlds) return;
std::map<int, HelloWorld *,
std::less<int, HelloWorld *> >::iterator
p =
g_helloWorlds->find(_num);
if (p !=
datas.end())
(*p).second->display();
}
§
exec.c
#include
"mylibtest.h"
int main()
{
HelloWorldInit();
HelloWorldCreate(12);
HelloWorldCreate(4);
HelloWorldCreate(25);
HelloWorldDisplay(12);
HelloWorldDisplay(4);
HelloWorldRelease(12);
HelloWorldDisplay(25);
HelloWorldRelease(4);
HelloWorldRelease(25);
HelloWorldDeinit();
return 1;
}
|