[29] Interfacer le C et le C++

(Une partie de C++ FAQ Lite fr, Copyright © 1991-2002, Marshall Cline, cline@parashift.com)

Traduit de l'anglais par Philippe Elie

Les FAQs de la section [29]


[29.1] Qu'ai-je besoin de savoir si je mélange du C et du C++?
Il y a plusieurs point a connaître: De plus vous devez lire les sections suivantes pour savoir comment écrire des fonctions C/C++ appelable depuis le C/C++.

[ Haut | Bas | Rechercher ]


[29.2] Comment inclure un fichier entête C dans mon source C++??
[Récemment ajouté type de retour de main() (le 10/99).]

Pour inclure un fichier entête standard (telle que <stdio.h>), vous n'avez rien d'inhabituel a faire. E.g.,

// Ceci est du code C++
#include <stdio.h> // Note: rien d'inhabituel dans cette ligne #include

int main()
{
printf("Hello world\n"); // Note: rien d'inhabituel dans cet appel
}

Note: Des directives différentes s'appliquent pour les fichiers en-têtes C non-systémes. Il y a deux cas: soit vous ne pouvez pas modifier le fichier entête , soit vous pouvez modifier le fichier entête .

[ Haut | Bas | Rechercher ]


[29.3] Comment inclure un fichier en-tête non-système dans mon code C++?
[Récemment ajouté type de retour de main() (le 10/99).]

Si vous incluez un fichier entête C qui n'est pas fournit par le système, vous pouvez avoir besoin d'inclure la ligne #include dans une construction extern C { /*...*/ }. Ceci indique au compilateur C++ que les fonctions déclarés dans ce fichiers entête sont des fonctions C.

// Ceci est du code C++

extern "C" {
// Fournir la déclaration de f(int i, char c, float x)
#include "my-C-code.h"
}

int main()
{
f(7, 'x', 3.14); // Note: rien d'inhabituel dans cette appel
}

Note: Des directives différentes s'appliquent pour les fichiers entêtes fournit par le système (tel que <stdio.h>) et pour les fichiers entêtes C que vous pouvez modifier .

[ Haut | Bas | Rechercher ]


[29.4] Comment modifier mes fichiers entête C pour facilité les #include dans mon code C++?
[Récemment ajouté type de retour de main() (le 10/99).]

Si vous incluez un fichier entête C qui n'est pas fourni par le système et si vous pouvez modifier ce fichier, vous devez considérer d'ajouter la construction extern C {...} dans le fichier entête pour faciliter son utilisation en C++. Les compilateurs C ne comprenant pas le sens de la construction extern C, vous devez inclure l'extern C { et la ligne } dans un bloc #ifdef ainsi les directives extern C { et la ligne } ne seront pas visibles par un compilateur C.

Etape #1: mettre les lignes suivantes au début de votre fichier entête (note: le symbole __cplusplus est #define si et seulement si le compilateur est un compilateur C++):

#ifdef __cplusplus
extern "C" {
#endif

Etape #2: mettre les lignes suivantes a la fin de votre fichier entête C:

#ifdef __cplusplus
}
#endif

Maintenant vous pouvez #include votre entête C sans extern C dans votre code C++:

// Ceci est du code C++

// Obtenir la déclaration de f(int i, char c, float x)
#include "my-C-code.h" // Note: rien d'inhabituel dans ce #include

int main()
{
f(7, 'x', 3.14); // Note: rien d'inhabituel dans cet appel
}

Note: Des directives différentes s'appliquent pour les fichier entête C système (tel que<stdio.h>) et pour les fichier entête C que vous ne pouvez pas modifier .

[ Haut | Bas | Rechercher ]


[29.5] Comment appeler une fonction C (non-systéme) f(int,char,float) depuis mon code C++?
[Récemment ajouté type de retour de main() (le 10/99).]

Si vous avez une fonction C que vous voulez appeler, et que pour une raison ou une autre vous ne voulez ou ne pouvez pas inclure le fichier entête dans lequel cette fonction est déclarée vous pouvez déclarer cette fonction C en utilisant la directive extern "C". Naturellement vous devez utiliser le prototype complet de la fonction:

extern "C" void f(int i, char c, float x);

Plusieurs fonctions C peuvent être regroupées au sein d'un bloc via des accolades:

extern "C" {
void f(int i, char c, float x);
int g(char* s, const char* s2);
double sqrtOfSumOfSquares(double a, double b);
}

Après cela vous pouvez appeler la fonction comme si c'était une fonction C++:

int main()
{
f(7, 'x', 3.14); // Note: rien d'inhabituel dans cet appel
}

[ Haut | Bas | Rechercher ]


[29.6] Comment créer une fonction C++ f(int,char,float) appelable depuis mon code C?
Le compilateur C++ doit savoir que la fonction f(int,char,float)peut-être appelée depuis C. On utilise pour cela la syntaxe extern C

// Ceci est du code C++

// Déclare f(int,char,float) en utilisant extern C:
extern "C" void f(int i, char c, float x);

// ...

// Définit f(int,char,float) dans un module C++ :
void f(int i, char c, float x)
{
// ...
}

La ligne extern "C" indique au compilateur que les conventions d'appel et la décoration (name mangling) utilise les conventions du C (E.g., nom précédé par un souligné). La surcharge de fonction n'étant pas supporté par les compilateurs C, vous ne pouvez pas avoir plusieurs fonctions de même nom appelable depuis du code C.

[ Haut | Bas | Rechercher ]


[29.7] Pourquoi le lieur génère des erreurs pour des fonctions C/C++ appelé depuis des fonctions C++/C?
Si vous n'avez pas utilisé la syntaxe extern Ccorrectement, vous aurez des erreurs provenant du lieur plutôt que des erreurs lors de la compilation. Ceci est du au fait que les compilateurs C++ "décorent" (mangle) les noms de fonctions (e.g. pour supporter la surcharge de fonction) différemment des compilateurs C.

Voir les deux FAQs précédentes pour l'utilisation de extern C.

[ Haut | Bas | Rechercher ]


[29.8] Comment passer un objet C++ de/vers une fonction C?
Voici un exemple (pour de l'information sur extern C, voir les deux FAQs précédentes).

Fred.h:

/* Ce fichier entête peut être lu par un compilateur C et un compilateur C++ */
#ifndef FRED_H
#define FRED_H

#ifdef __cplusplus
class Fred {
public:
Fred();
void wilma(int);
private:
int a_;
};
#else
typedef
struct Fred
Fred;
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if defined(__STDC__) || defined(__cplusplus)
extern void c_function(Fred*); /* ANSI-C prototypes */
extern Fred* cplusplus_callback_function(Fred*);
#else
extern void c_function(); /* K&R style */
extern Fred* cplusplus_callback_function();
#endif

#ifdef __cplusplus
}
#endif

#endif /*FRED_H*/

Fred.cpp:

// Ceci est du code C++

#include "Fred.h"

Fred::Fred() : a_(0) { }

void Fred::wilma(int a) { }

Fred* cplusplus_callback_function(Fred* fred)
{
fred->wilma(123);
return fred;
}

main.cpp:

// Ceci est du code C++

#include "Fred.h"

int main()
{
Fred fred;
c_function(&fred);
return 0;
}

c-function.c:

/* Ceci est du code C */

#include "Fred.h"

void c_function(Fred* fred)
{
cplusplus_callback_function(fred);
}

Passer des pointeurs vers des objets C++ de ou vers des fonctions C échouera si vous passez ou recevez des pointeurs qui n'ont pas exactement le même type. Par exemple, ne passez pas un pointeur de classe de base alors que la fonction appelée attend un pointeur vers une classe dérivée, car votre compilateur C ne saura pas faire les conversions nécessaires.

[ Haut | Bas | Rechercher ]


[29.9] Ma fonction C peut-elle accéder directement au donnés membres d'un objet C++?
Parfois.

(Pour des informations basiques sur le passage d'objets C++ vers ou de fonctions C, lisez la FAQ précédente).

Vous pouvez accéder de façon sûr a des données d'un objet C++ a partir d'un fonction C si la classe C++:

Si la classe C++ a une classe de base (ou si un membre objet a un classe de base), accéder aux données sera techniquementnon-portable, puisque la disposition des classesen mémoire n'est pas imposé par le langage. toutefois en pratique, tout les compilateurs C++ disposent les classes de base de la même manière: la classe de base apparaît d'abord (dans l'ordre gauche-droite dans le cas d'héritage multiple), et les objets membres suivent. (N.D.T. : ceci est faux de nos jours : Borland C++ par exemple n'utilise pas la même disposition suivant les versions de ces compilateurs)

En outre, si la classe (ou une de ces classes de base) contient une fonction virtuel, la plupart des compilateurs C++ mettrons un void* dans l'objet soit à l'emplacement de la première fonction virtual ou au tout début de l'objet. A nouveau ceci n'est pas requis par le langage, mais c'est de cette façon que "tous" les compilateurs C++ font.

Si la classe a un classe de base virtual, alors c'est encore plus complexe et moins portable. Une implémentation courante des classes de base virtuel (V) est de placer un objet V a la fin de la classe (sans tenir compte de l'ordre d'héritage). Le reste de l'objet apparaît en ordre normal. Chaque classe dérivé qui possède une classe de base V possède un pointeur vers V.

[ Haut | Bas | Rechercher ]


[29.10] Pourquoi je me sens "plus loin de la machine" en C++ vs en C?
Vous l'êtes.

Comme tout langage Orienté Objet, C++ permet de modéliser le domaine du problème lui-même, ce qui permet de programmer dans le langage du domaine du problème plutôt que dans le langage du domaine des solutions.

Une des grandes forces du C est le fait qu'il ne possède pas de "mécanismes cachés": ce que vous voyez est ce que vous avez. Vous pouvez lire un programme C et "voir" chaque cycle d'horloge. Ce n'est pas le cas en C++; les anciens programmeurs en C (comme beaucoup d'entre nous le sont) sont souvent ambivalent (peut-on dire, "hostile"?) a propos de cette caractéristiques. Toutefois après avoir fait le transition vers l'Orienté Objet, ils réalisent souvent que bien que le C++ cache certains mécanismes de fonctionnement au programmeur, il fournit aussi un niveau d'abstraction et une économie d'expression qui diminue le coût de maintenance sans porter atteinte aux performances.

Naturellement vous pouvez écrire du mauvais code avec n'importe quelle langage; C++ ne garantit pas un niveau particulier de qualité, de réutilisabilité, d'abstraction, ou toute autre mesure "bien".

C++ n'essaie pas de rendre impossible au mauvais programmeurs d'écrire de mauvais programme; il rend seulement possible au programmeur raisonnable d'écrire du logiciel de qualité.

[ Haut | Bas | Rechercher ]


E-mail Marshall Cline Ecrire à l'auteur, au traducteur, ou en savoir plus sur la traduction.
C++ FAQ Lite fr | Table des matières | Index | A propos de l'auteur | © | Téléchargez votre propre copie ]
Dernière révision Sun Apr 13 23:54:27 PDT 2003