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

bibliotheque et fichiers d'en-tete pour l'utilisateur

50 réponses
Avatar
Vincent Lefevre
Bonjour et bonne année,

J'aimerais avoir votre avis sur le point suivant (je n'ai pas vu
d'indications dans les FAQ). Dans la bibliothèque qu'on développe
(MPFR), il y a des fonctions qui ne sont liées aucunement à la
bibliothèque standard et d'autres qui sont liées à certaines choses
de <stdio.h> (par exemple utilisent FILE en argument, parce que ce
sont des fonctions d'entrées/sorties). Y a-t-il une ou des solutions
recommandées concernant les fichiers d'en-tête fournis par la
bibliothèque (pour l'utilisateur de la bibliothèque), avec une
volonté de portabilité?

1) La solution actuelle est celle de GMP, qui est d'essayer de
détecter automatiquement si <stdio.h> a été #inclus avant gmp.h,
auquel cas gmp.h déclare les fonctions d'entrées/sorties. Mais cela
pose notamment deux gros problèmes: comme il n'y a pas de standard
pour cette détection, cela risque d'échouer sur les plateformes non
testées (et cela arrive en pratique) ou à cause de changements futurs
sur les plateformes existantes (cf tous les problèmes qu'a posés le
changement lié au errno dans la glibc); d'autre part, cette méthode
empiète sur le domaine de l'utilisateur. Par exemple, le programme
suivant ne compile pas:

#define H_STDIO 1
#include <gmp.h>

int main(void)
{
return 0;
}

(à noter que H_STDIO ne fait pas partie des macros réservées par GMP,
qui commencent par "GMP_", par convention).

2) Il y a la solution d'inclure systématiquement <stdio.h> dans le
fichier d'en-tête qu'on fournit (mpfr.h), éventuellement sauf si telle
macro, e.g. MPFR_NO_STDIO, est définie auparavant par l'utilisateur
(évidemment, tout cela devant être parfaitement documenté...).

3) Il y a la solution de fournir plusieurs fichiers d'en-tête, e.g.
mpfr.h et mpfrIO.h, où <stdio.h> n'est inclus que dans "mpfrIO.h".
C'est une sorte de (2) modulaire.

Dans les quelques bibliothèques que j'ai regardées (à part GMP), c'est
soit (2) sans la possibilité d'empêcher l'inclusion, soit (3).

Pour info, ma préférence personnelle va pour (3), pour son aspect
modulaire en particulier.

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

10 réponses

1 2 3 4 5
Avatar
Vincent Lefevre
Dans l'article ,
Gabriel Dos Reis écrit:

Je suis étonné de voir que tu te préoccupes plus de <stdio.h> que de
<stdlib.h> -- qui contient malloc().


On n'inclut pas <stdlib.h> dans mpfr.h. La préoccupation concernant
<stdio.h>, c'est surtout pour fixer une API stable le plus tôt
possible.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Vincent Lefevre <vincent+ wrote:

<stdio.h> n'est pas dans la liste. Maintenant, si toutes les
implémentations freestanding fournissent un <stdio.h> similaire
à de l'hébergé, alors OK.


Je vois. En fait <stdio.h> est le plus souvent livré avec la bibliothèque qui
va bien. simplement il faut ecrire la fonction de bas niveau qui
implémentente fgetc() et fputc() en fonction de la cible. (Généralement un
port série). Une fois fait, on a stdin, stdout et stderr. Sinon, par defaut,
c'est parfois des fonctions qui envoient/reçoivent des caractères dans/d' une
console de debug de l'émulateur...

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Erwan David wrote:

Non. Si tu es en freestanding tu n'utilise *pas* stdio.h
Jamais.


Je ne vois pas pourquoi. Je fais ça tous les jours depuis 10 ans. Je ne suis
pas mort...

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Erwan David wrote:

C'est pour éviter ce genre de problème que je préfère nettement la
garde systématique contre les inclusions multiples et l'inclusion
systématique dans tous les en-têtes de ce qu'il faut pour pouvoir les
parser.


Je suis d'accord.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
espie
In article ,
Erwan David wrote:
Euh, je ne vois pas ce qui pourrais provoquer ça. Les problèmes
d'ordre d'inclusion apparaissent quand a.h n'inclus pas b.h mais n'est
pas parsable sans l'avoir inclus (par exemple parceque a.h déclare une
fonction utilisant un type déclaré dans b.h)
Les entetes qui parfois ont des definitions supplementaires que tu n'as

pas prevues, et qui posent des problemes de portabilite parce qu'elles
collisionnent avec d'autres choses, et uniquement sur certains systemes.

C'est pour éviter ce genre de problème que je préfère nettement la
garde systématique contre les inclusions multiples et l'inclusion
systématique dans tous les en-têtes de ce qu'il faut pour pouvoir les
parser.


D'experience, je considere de plus en plus que c'est une erreur. C'est
toujours infiniment plus simple de modifier le fichier final
(eventuellement avec quelques scripts) que de corriger des entetes
defectueux. Deja, avec des entetes defectueux, il faut se retrouver dans
le bon entete, reconstituer l'ordre d'inclusion (ce qui n'est pas simple,
car il faut suivre l'arbre des entetes, ET prendre en compte gardes et
inclusions multiples). Le pire etant, a mon avis, les entetes qu'on peut
inclure plusieurs fois et qui ont des comportements differents selon les
#define en vigueur. Ne me dis pas que tu n'as jamais vu des bouts de
logiciel qui font du #define _POSIX_SOURCE, d'autres qui font du
#define _XOPEN_WHATEVER, et les deux qui ont un peu de mal a collaborer
lorsqu'on met les bouts ensemble.

Le choix des entetes a inclusion multiple ne fonctionne guere que dans
un monde ideal ou les gens ecrivent toujours des entetes parfaits,
connaissent bien la norme C, et ou les compilateurs vont tres vite et
sont non buggues.

Le monde auquel j'ai affaire est helas bien moins propre. Et j'avoue que
j'en ai un peu marre, lorsque je porte des logiciels d'un OS a l'autre,
de tomber sur des constructions super-intelligentes qu'il me faut passer
du temps a contourner parce que, bien sur, la superbe construction ne
fonctionne pas parce que l'auteur de la construction a des oeilleres et
a `oublie' quelques cas de figure qu'il n'a jamais rencontre dans sa
construction. Comparativement, ca va bien plus vite de corriger des
solutions plus simples, un peu plus manuelles, mais sur lesquelles on
peut facilement comprendre ce qui se passe sans devoir sortir l'artillerie
lourde a la gcc -E -dM + une dizaine de grep pour comprendre ce qui se
passe.

Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article ,
| Gabriel Dos Reis écrit:
|
| > Cas concret où tu vas porter ta bibliothèque (qui, si j'ai bien
| > compris utilise GMP) ET où l'environment est freestanding.
|
| Ah... Le but est de prévoir le maximum de situations possibles dès
| maintenant d'une part pour éviter d'avoir à faire des modifications

je comprends, mais ce qui serait utile, c'est de prevoir des
situations pratiques possibles, et pas toutes les situations
possibles :-).

Quand tu travailles dans un freestanding, ce qui va te potentiellement
poser probleme, ce n'est pas FILE*, mais malloc() ou autres
joyeuseutes utilisees dans GMP. Ton FILE*, tu as juste besoin pour
declarer des fonctions; tu n'est pas oblige de les /definir/ si ton
environnement ne supporte pas les I/O avec FILE*.
Par contre tu vas de vrais soucis avec malloc() et autres.

[...]

| > Mon hypothèse (tout à fait arrogante mais réaliste) est tu peux
| > imaginer de telles situations, mais elles ne se réalisent que dans
| > l'abstrait, i.e. pas concretement.
|
| Mais comment savoir si elles vont se réaliser contrètement ou non?

Le bon sens :-) :-)

-- Gaby
Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article ,
| Gabriel Dos Reis écrit:
|
| > Je suis étonné de voir que tu te préoccupes plus de <stdio.h> que de
| > <stdlib.h> -- qui contient malloc().
|
| On n'inclut pas <stdlib.h> dans mpfr.h.

Oui, mais si tu utilises GMP, tu utilises malloc() non ?

| La préoccupation concernant
| <stdio.h>, c'est surtout pour fixer une API stable le plus tôt
| possible.

ma recommandation serait : inclus <stdio.h> pour les declarations de
fonctions qui en ont besoin. Dans les fichiers d'implementations, tu
ne definis pas les fonctions que tu penses "problematiques".

-- Gaby
Avatar
Gabriel Dos Reis
(Marc Espie) writes:

| Le choix des entetes a inclusion multiple ne fonctionne guere que dans
| un monde ideal ou les gens ecrivent toujours des entetes parfaits,
| connaissent bien la norme C, et ou les compilateurs vont tres vite et
| sont non buggues.

Bah non, pas forcement.

-- Gaby
Avatar
Vincent Lefevre
Dans l'article ,
Gabriel Dos Reis écrit:

je comprends, mais ce qui serait utile, c'est de prevoir des
situations pratiques possibles, et pas toutes les situations
possibles :-).


Je considérais la situation du <stdio.h> absent parce qu'elle était
simple à traiter: quelques lignes à ajouter et un peu de documentation.
Ceci dit...

Quand tu travailles dans un freestanding, ce qui va te potentiellement
poser probleme, ce n'est pas FILE*, mais malloc() ou autres
joyeuseutes utilisees dans GMP. Ton FILE*, tu as juste besoin pour
declarer des fonctions; tu n'est pas oblige de les /definir/ si ton
environnement ne supporte pas les I/O avec FILE*.


Pour le FILE *, je suppose qu'il est plus pratique alors pour l'utilisateur
d'un tel système de créer un fichier stdio.h pour que tout se parse sans
problème. Concernant le malloc(), on appelle pour le moment le wrapper de
GMP, où l'utilisateur peut définir ses propres fonctions d'allocation, ce
qui fait que cela ne posera pas forcément de problème.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Vincent Lefevre
Dans l'article ,
Gabriel Dos Reis écrit:

Vincent Lefevre <vincent+ writes:

| On n'inclut pas <stdlib.h> dans mpfr.h.

Oui, mais si tu utilises GMP, tu utilises malloc() non ?


On n'a aucun appelle à malloc().

| La préoccupation concernant <stdio.h>, c'est surtout pour fixer
| une API stable le plus tôt possible.

ma recommandation serait : inclus <stdio.h> pour les declarations de
fonctions qui en ont besoin. Dans les fichiers d'implementations, tu
ne definis pas les fonctions que tu penses "problematiques".


Ma question concernant <stdio.h> était uniquement pour le fichier
mpfr.h.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/> - 100%
validated (X)HTML - Acorn Risc PC, Yellow Pig 17, Championnat International
des Jeux Mathématiques et Logiques, TETRHEX, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

1 2 3 4 5