Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Utiliser une bibliothèque prévue pour du C++

4 réponses
Avatar
Thomas Baruchel
Bonjour,

j'aimerais pouvoir utiliser dans un programme en C une bibliothèque
écrite en C++ proposant une interface pour le C++ (fichier .h) mais
aussi pour du fortran 90 (ce qui me laisse penser qu'il y a une
certaine souplesse dans l'utilisation de la bibliothèque, même si la
seconde interface semble légèrement plus restreinte (à en croire la
description officielle) que l'autre. Dans la mesure où je suis habitué
à appeler quelque chose d'écrit en C depuis du Fortran, je me demande
dans quelle mesure je pourrais ici appeler la bibliothèque depuis du C.
Comme je ne connais pas le C++, je ne sais pas trop que faire ; je
pense que le meilleur groupe pour poser la questio est bien ici car
c'est vraiment la solution en C qui m'intéresse. Je copie le fichier .h
pour donner une idée de ce dont il s'agit (il s'agit de la bibliothèqe QD :
http://crd.lbl.gov/~dhbailey/mpdist/qd.tar.gz écrite par Bailey).

/*
* include/qd.h
*
* This work was supported by the Director, Office of Science, Division
* of Mathematical, Information, and Computational Sciences of the
* U.S. Department of Energy under contract number DE-AC03-76SF00098.
*
* Copyright (c) 2000-2001
*
* Quad-double precision (>= 212-bit significand) floating point arithmetic
* package, written in ANSI C++, taking full advantage of operator overloading.
* Uses similar techniques as that of David Bailey's double-double package
* and that of Jonathan Shewchuk's adaptive precision floating point
* arithmetic package. See
*
* http://www.nersc.gov/~dhbailey/mpdist/mpdist.html
* http://www.cs.cmu.edu/~quake/robust.html
*
* for more details.
*
* Yozo Hida
*/
#ifndef _QD_H_
#define _QD_H_

#include <iostream>
#include "dd.h"

using std::ostream;
using std::istream;

class qd_real {
protected:
double x[4]; /* The Components. */

/* Eliminates any zeros in the middle component(s). */
void zero_elim();
void zero_elim(double &e);

void renorm();
void renorm(double &e);

void quick_accum(double d, double &e);
void quick_prod_accum(double a, double b, double &e);

/* Computes qd * d where d is known to be a power of 2.
This can be done component wise. */
friend qd_real mul_pwr2(const qd_real &qd, double d);

/* Sin / Cos Tables */
static const qd_real _pi1024; /* Used in sin / cos routine. */
static const qd_real sin_table[];
static const qd_real cos_table[];

public:
/* Protected Constructor. */
qd_real(double x0, double x1, double x2, double x3);


/* Useful constants. */
static const qd_real _2pi;
static const qd_real _pi;
static const qd_real _3pi4;
static const qd_real _pi2;
static const qd_real _pi4;
static const qd_real _pi8;
static const qd_real _e;
static const qd_real _log2;
static const qd_real _log10;

static const double _eps; /* = 2^-212. */

/* Constructors */
qd_real() {}
qd_real(const char *s);
qd_real(const dd_real &dd);
qd_real(double d);
qd_real(int i);

/* Member Access */
double operator[](int i) const;

static void abort();

/* Addition */
friend qd_real operator+(const qd_real &a, const qd_real &b);
friend qd_real operator+(const dd_real &a, const qd_real &b);
friend qd_real operator+(const qd_real &a, const dd_real &b);
friend qd_real operator+(const qd_real &a, double b);
friend qd_real operator+(double a, const qd_real &b);

/* Self-Addition */
qd_real &operator+=(double a);
qd_real &operator+=(const dd_real &a);
qd_real &operator+=(const qd_real &a);

/* Subtraction */
friend qd_real operator-(const qd_real &a, const qd_real &b);
friend qd_real operator-(const dd_real &a, const qd_real &b);
friend qd_real operator-(const qd_real &a, const dd_real &b);
friend qd_real operator-(const qd_real &a, double b);
friend qd_real operator-(double a, const qd_real &b);

/* Self-Subtraction */
qd_real &operator-=(double a);
qd_real &operator-=(const dd_real &a);
qd_real &operator-=(const qd_real &a);

/* Multiplication */
friend qd_real operator*(const qd_real &a, const qd_real &b);
friend qd_real operator*(const dd_real &a, const qd_real &b);
friend qd_real operator*(const qd_real &a, const dd_real &b);
friend qd_real operator*(const qd_real &a, double b);
friend qd_real operator*(double a, const qd_real &b);

/* Self-Multiplication */
qd_real &operator*=(double a);
qd_real &operator*=(const dd_real &a);
qd_real &operator*=(const qd_real &a);

/* Division */
friend qd_real operator/(const qd_real &a, const qd_real &b);
friend qd_real operator/(const dd_real &a, const qd_real &b);
friend qd_real operator/(const qd_real &a, const dd_real &b);
friend qd_real operator/(const qd_real &a, double b);
friend qd_real operator/(double a, const qd_real &b);

/* Self-Division */
qd_real &operator/=(double a);
qd_real &operator/=(const dd_real &a);
qd_real &operator/=(const qd_real &a);

/* Square, Square Root, Power, N-th Root. */
friend qd_real sqr(const qd_real &a);
friend qd_real sqrt(const qd_real &a);
friend qd_real pow(const qd_real &a, int n);
friend qd_real npwr(const qd_real &a, int n);
qd_real operator^(int n) const;
friend qd_real nroot(const qd_real &a, int n);

/* Unary Minus */
qd_real operator-() const;

/* Remainder */
friend qd_real rem(const qd_real &a, const qd_real &b);
friend qd_real drem(const qd_real &a, const qd_real &b);
friend qd_real divrem(const qd_real &a, const qd_real &b, qd_real &r);

/* Cast */
operator dd_real() const;
operator double() const;
operator int() const;

/* Equality Comparison */
friend bool operator==(const qd_real &a, const qd_real &b);
friend bool operator==(const qd_real &a, const dd_real &b);
friend bool operator==(const dd_real &a, const qd_real &b);
friend bool operator==(double a, const qd_real &b);
friend bool operator==(const qd_real &a, double b);

/* Less-Than Comparison */
friend bool operator<(const qd_real &a, const qd_real &b);
friend bool operator<(const qd_real &a, const dd_real &b);
friend bool operator<(const dd_real &a, const qd_real &b);
friend bool operator<(double a, const qd_real &b);
friend bool operator<(const qd_real &a, double b);

/* Greater-Than Comparison */
friend bool operator>(const qd_real &a, const qd_real &b);
friend bool operator>(const qd_real &a, const dd_real &b);
friend bool operator>(const dd_real &a, const qd_real &b);
friend bool operator>(double a, const qd_real &b);
friend bool operator>(const qd_real &a, double b);

/* Less-Than-Or-Equal-To Comparison */
friend bool operator<=(const qd_real &a, const qd_real &b);
friend bool operator<=(const qd_real &a, const dd_real &b);
friend bool operator<=(const dd_real &a, const qd_real &b);
friend bool operator<=(double a, const qd_real &b);
friend bool operator<=(const qd_real &a, double b);

/* Greater-Than-Or-Equal-To Comparison */
friend bool operator>=(const qd_real &a, const qd_real &b);
friend bool operator>=(const qd_real &a, const dd_real &b);
friend bool operator>=(const dd_real &a, const qd_real &b);
friend bool operator>=(double a, const qd_real &b);
friend bool operator>=(const qd_real &a, double b);

/* Not-Equal-To Comparison */
friend bool operator!=(const qd_real &a, const qd_real &b);
friend bool operator!=(const qd_real &a, const dd_real &b);
friend bool operator!=(const dd_real &a, const qd_real &b);
friend bool operator!=(double a, const qd_real &b);
friend bool operator!=(const qd_real &a, double b);

/* Other Comparisons. These are faster than directly
comparing to 0 or 1. */
bool is_zero() const;
bool is_one() const;
bool is_positive() const;
bool is_negative() const;

/* Micellaneous algebraic operations */
friend qd_real fabs(const qd_real &a);
friend qd_real abs(const qd_real &a); /* same as fabs */

/* Computes a * 2^n. */
friend qd_real ldexp(const qd_real &a, int n);

/* Rounding */
friend qd_real nint(const qd_real &a);
friend qd_real quick_nint(const qd_real &a);
friend qd_real floor(const qd_real &a);
friend qd_real ceil(const qd_real &a);
friend qd_real aint(const qd_real &a);

/* Trigonometric Functions */
friend qd_real sin(const qd_real &a);
friend qd_real cos(const qd_real &a);
friend qd_real tan(const qd_real &a);
friend void sincos(const qd_real &a, qd_real &s, qd_real &c);

/* Inverse Trigonometric Functions */
friend qd_real asin(const qd_real &a);
friend qd_real acos(const qd_real &a);
friend qd_real atan(const qd_real &a);
friend qd_real atan2(const qd_real &y, const qd_real &x);

/* Exponential / Logarithm */
friend qd_real exp(const qd_real &a);
friend qd_real log(const qd_real &a);
friend qd_real log10(const qd_real &a);

/* Hyperbolic Functions */
friend qd_real sinh(const qd_real &a);
friend qd_real cosh(const qd_real &a);
friend qd_real tanh(const qd_real &a);
friend void sincosh(const qd_real &a, qd_real &sin_qd, qd_real &cos_qd);

/* Inverse Hyperbolic Functions */
friend qd_real asinh(const qd_real &a);
friend qd_real acosh(const qd_real &a);
friend qd_real atanh(const qd_real &a);

/* Random Number */
static qd_real rand(void);
friend qd_real qdrand(void);

/* Min / Max */
friend qd_real max(const qd_real &a, const qd_real &b);
friend qd_real max(const qd_real &a, const qd_real &b, const qd_real &c);
friend qd_real min(const qd_real &a, const qd_real &b);
friend qd_real min(const qd_real &a, const qd_real &b, const qd_real &c);

/* Polynomial Evaluator / Solver */
friend qd_real polyroot(const qd_real *c, int n,
const qd_real &x0, double thresh = 1.0e-62);
friend qd_real polyeval(const qd_real *c, int n, const qd_real &x);

/* Input / Output */
friend ostream &operator<<(ostream &s, const qd_real &a);
friend istream &operator>>(istream &s, qd_real &a);

void write(char *s, int d = 64) const; /* Note: s must hold d+8 chars. */
static int read(const char *s, qd_real &a);

/* Debugging methods */
void dump_components() const;
void dump_bits() const;
void dump() const;

static qd_real debug_rand();

};

qd_real qdrand(void);

#ifndef NO_INLINE
#include "qd_inline.h"
#endif

#endif /* _QD_H_ */

--
Thomas Baruchel --- Home Page: http://baruchel.free.fr/~thomas/
write to baruchel at the host called bluebottle dot com
écrire à baruchel chez l'hôte nommé bluebottle point com
(you will be asked for a confirmation the first time you write)

4 réponses

Avatar
Anthony Fleury
Bonjour,


Bonjour,

j'aimerais pouvoir utiliser dans un programme en C une bibliothèque
écrite en C++ proposant une interface pour le C++ (fichier .h) mais
aussi pour du fortran 90 (ce qui me laisse penser qu'il y a une
certaine souplesse dans l'utilisation de la bibliothèque, même si la
seconde interface semble légèrement plus restreinte (à en croire la
description officielle) que l'autre.


Bah ce n'est pas si souple que ca en a l'air...

Dans la mesure où je suis habitué
à appeler quelque chose d'écrit en C depuis du Fortran, je me demande
dans quelle mesure je pourrais ici appeler la bibliothèque depuis du C.
Comme je ne connais pas le C++, je ne sais pas trop que faire ; je
pense que le meilleur groupe pour poser la questio est bien ici car
c'est vraiment la solution en C qui m'intéresse. Je copie le fichier .h
pour donner une idée de ce dont il s'agit (il s'agit de la bibliothèqe QD :
http://crd.lbl.gov/~dhbailey/mpdist/qd.tar.gz écrite par Bailey).


Il faudrait savoir exactement ce qui est prévu de faire de cette
bibliothèque. Si j'ai bien vu, elle offre des nombres à plus haute
précision que ce qu'exige la norme. Soit.
Voyons ce fichier .h :

[...]

class qd_real {
protected:
double x[4]; /* The Components. */


[...]

friend qd_real operator+(const qd_real &a, const qd_real &b);


Elle offre : une classe pour les réels (une sorte de structure mais qui
peut contenir des fonctions, possède un constructeur etc... (en très
gros, désolé pour les puristes C++, c'est pour le bien de
l'explication). Et pour cette classe, on définit des opérateurs. En C++
on peut surcharger les opérateurs, donc une opération telle que :

qd_real a, b, c;

a = b+c; appelera operator+(b, c) et mettra le resultat dans a.

En gros, ce n'est donc pas facile de s'interfacer en C avec ceci pour
utiliser leurs nombres réels... Il faut refaire une interface, donc
refaire le boulot qui a dû être fait pour Fortran 90... Bonne chance :-)
Là où ca se fait ce sont pour des bibliothèques prévues pour, avec des
extern "C" et pour appeler des fonctions. Mais là pour utiliser une
classe...

Ou alors j'ai loupé un truc, et j'attends des corrections.

--
Anthony Fleury

Avatar
Thierry Perrin
Bonjour,



Pour l'avoir fait de façon ponctuelle sur des dll, il n'est pas possible d'appeler
directement du C++ à partir du C en C pure. Il faut pour certain compilateur
utiliser de l'assembleur. Par exemple msdev utilise le registre ecx sur
Pentium pour transférer this à la méthode. Ensuite vient le problème de la
décoration (mangling). Les symboles exportés par les compilateurs C++ sont
adaptés pour éviter de violer les règles du C++ au moment de l'édition de
liens des fichiers objets. On trouve des choses du genre ?? Ce
qui ne constitue pas un identifieur valide pour le langage C. Ce dernier
problème peut être contourner s'il est possible d'utiliser une bibliothèque
partagée (.dll ou .so).



Thierry Perrin
Avatar
Anthony Fleury
Bonjour,


Bonjour,

[...]

Ensuite vient le problème de la
décoration (mangling). Les symboles exportés par les compilateurs C++ sont
adaptés pour éviter de violer les règles du C++ au moment de l'édition de
liens des fichiers objets. On trouve des choses du genre ?? Ce
qui ne constitue pas un identifieur valide pour le langage C. Ce dernier
problème peut être contourner s'il est possible d'utiliser une bibliothèque
partagée (.dll ou .so).


<HS>

C'est surtout qu'un compilateur C++ devra faire avec ce qui la
surcharge. Il devra donc adapter le nom des fonctions avec le type
d'arguments qu'elle recoit, afin de ne pas avoir deux fonctions avec le
même identifiant au final (void f(void) et void f(int) aurait le même
identifiant avec la convention à la C). Cette décoration n'est pas
décrite dans la norme donc tous les compilateurs la font comme ils
veulent (ce qui est embetant pour les programmeurs de ce langage car une
bibliothèque est prévue pour un compilateur précis à cause de ceci).

Quand le programmeur a prévu que sa fonction sera appelée à partir d'un
programme C, il déclarera le tout dans un bloc extern "C" ce qui fait
que les conventions d'appel seront les mêmes qu'en C. Ce n'est donc pas
spécifique aux bibliothèques partagées, il faut que la convention
d'appel "à la C" ait été prévue par le programmeur C++. Bien sûr, on ne
pourra pas avoir de surcharge de fonction dans un bloc extern "C" vu que
le C l'interdit.

</HS>

--
Anthony Fleury

Avatar
Thomas Baruchel
Quand le programmeur a prévu que sa fonction sera appelée à partir d'un
programme C, il déclarera le tout dans un bloc extern "C" ce qui fait


Je vous remercie tous les deux pour vos réponses ; en fait, je ne m'étais
pas rendu compte que le programmeur avait fait un gros effort d'interfaçage
qui permattait d'utiliser la bibliothèque depuis du C++ et du Fortran, mais
aussi... depuis du C. Entre temps, j'ai codé mon projet en Fortran, donc
tant pis, mais à l'avenir je saurais que le C a été prévu.

Cordialement,

--
Thomas Baruchel --- Home Page: http://baruchel.free.fr/~thomas/
write to baruchel at the host called bluebottle dot com
écrire à baruchel chez l'hôte nommé bluebottle point com
(you will be asked for a confirmation the first time you write)