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

Y a-t-il des lacunes dans la norme ISO C90 ?

61 réponses
Avatar
Fabrice
Bonjour,

Un collègue m'a posé une question à laquelle je fus incapable de
répondre : si on suit strictement la norme ISO C90 est-on garanti
d'avoir un programme portable partout ?

Par 'portable partout' j'entends que le programme compilé par n'importe
quel compilateur (respectant la norme) sur n'importe quelle architecture
donne le même résultat (aux erreurs de précision numérique et aux bugs
du compilateur près).

La véritable question est en fait de savoir si la norme est suffisante
ou bien s'il y a des lacunes dedans pour garantir qu'un programme sera
portable.

Si la norme ne suffit pas, pourriez-vous m'indiquer un sous-ensemble de
la norme pouvant garantir la portabilité ?

Merci d'avance !

10 réponses

1 2 3 4 5
Avatar
Antoine Leca
En , Fabrice va escriure:

D'accord. Comme je l'ai écris aux autres il faut donc que dans mon
manuel de codage je précise "Respectez la norme ET n'utilisez pas de
comportement non défini par la norme"


Pléonasme.

Soit on « suit strictement » [sic], et il n'y a pas de comportement non
défini.

Soit on suit la norme, mais pas strictement, c'est-à-dire on écrit en C,
comme les millions de programmeurs avant toi qui ont pondu les milliards de
lignes qui existent, mais alors il n'y a plus l'assurance.


Ce code est parfaitement 'légal' (il ne brise aucune regle écrite),



C'est un comportement explicitement indéfini (C90 6.1.4, C99 6.4.5p6). C'est
utilisé pour une sortie, donc ce programme n'est pas strictement conforme.
« Légal » ou « illégal » n'existent pas ici, la norme C n'est pas une loi,
mais on peut apparenter 'légal' et 'strictement conforme'...


Antoine


Avatar
Antoine Leca
En , Fabrice va escriure:

Pour les problèmes de retours chariots, nous avons personnellement
opté pour la lecture binaire des fichiers textes. un parseur
contenant en mémoire tous les types de retour chariot de la création
a ensuite été utilisé (en pratique il ne contenait que la recherche
de "n" et de "rn").


Comment fais-tu avec mes fichiers (à plat, provenance mainframe): les fins
de ligne ne sont pas des caractères, mais des positions ?


Antoine

Avatar
Antoine Leca
En 20040410104520$, Vincent Lefevre va escriure:
Le contenu de stdout en tant qu'octets ou autre peut être tout aussi
important.


This International Standard does not specify
[...]

-- the mechanism by which output data are transformed after being produced
by a C program;





Antoine

Avatar
Antoine Leca
En , Fabrice va escriure:
Hmm... avec les réels (virgule flottante), tu n'as pas grand chose de
spécifié. L'implémentation peut déclarer suivre la norme IEEE 754
(mais en C99 seulement, je crois).



Et encore, pas toujours. __STDC_IEC_559__ pour le savoir.

Et rien n'est spécifié concernant les
fonctions transcendantes (cos, sin, atan...).


Je ne suis pas sûr de comprendre, est-ce que tout cela n'est pas lié
aux erreurs de précision numérique et aux bugs du compilateur ?


Non, c'est plus large.

Si j'utilise la fonction cosinus sur un réel quelconque (en respectant
les limites d'un double), n'aurais-je pas le même résultat partout
(aux erreurs de précision près) ?


Non. Ou alors, oui, à condition de considérer que les « erreurs de
précision » s'étendent de -1 à +1 ;-).

La norme ne garantit absolument rien dans ce domaine. Et la pratique non
plus, d'ailleurs. J'ai tendance à penser que cela justifie l'existence des
labos de QN ;-).

En fait, « un réel quelconque(en respectant les limites d'un double) »,
c'est vraiment beaucoup pour un cosinus... Aux environs de 1E+30, la
périodicité de 2 pi de la fonction devient un fait plutôt anecdotique, non ?
Si tu rajoutes pi à la valeur, le double ne va pas changer beaucoup. Alors
la précision du résultat...


printf avec des flottants n'est pas bien spécifié également.


Pareil, si je fais un printf("%1.15en", 123.456) est-ce que je
n'aurais pas le même résultat partout aux erreurs d'arrondi près ?


Soit tu le sais parfaitement et tu taquines, soit tu n'as pas assez
réfléchi.

Les ordinateurs travaillent pour la plupart en binaire (et les calculateurs
base 16 ou 10 deviennent chaque jour moins important). 123.456 est en
binaire une chaîne infinie 0x7B.787Aetc., comme 1/7 en base 10. Tu demandes
15 chiffres décimaux de précision, donc tu dépasses la précision de stockage
de double de la norme (10) et tu tutoies celle de la pratique (en IEEE 754).
Le résultat est par tant aléatoire au delà des six premiers caractères (qui,
s'il ne sont pas '1', '.', '2', '3', '4' et '5', indiqueraient un *gros*
bogue dans la bibliothèque C ;-)).

La norme (C99, pas C90) prescrit (ce n'est même pas garanti) la sortie
"1.234560000000000e+02n" en supposant le format IEEE-754/CÉI 60559 avec les
options par défaut. Je pense qu'il doit y avoir des paramétrages pour
justifier un résultat "1.234560000000001e+02n", mais je n'ai pas envie de
les chercher.


Antoine


Avatar
Laurent Wacrenier
Fabrice écrit:
Pour les entrées/sorties on peut fonctionner avec des fichiers textes.


Uniquement quand l'implémentation possède des fichiers.

Avatar
Vincent Lefevre
Dans l'article <c5g7iv$59u$,
Antoine Leca écrit:

En 20040410104520$, Vincent Lefevre va escriure:
Le contenu de stdout en tant qu'octets ou autre peut être tout aussi
important.


This International Standard does not specify
[...]

-- the mechanism by which output data are transformed after being produced
by a C program;


Tout à fait. Mais la question est de savoir ce qu'envoie en sortie un
programme C: des caractères (en faisant abstraction du codage) ou des
données numériques (e.g. des octets si un char fait 8 bits)? La norme
ne semble pas imposer exclusivement l'un de ces deux choix.

Donc la sortie de putchar('a'); dépend de l'implémentation, car le code
de 'a' n'est pas le même avec toutes les implémentations. De même, la
sortie de putchar(65); dépend de l'implémentation, car le 65 correspond
à un caractère dépendant de l'implémentation.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% validated (X)HTML - Acorn / RISC OS / ARM, free software, YP17,
Championnat International des Jeux Mathématiques et Logiques, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Vincent Lefevre
Dans l'article <c5g5o1$uor$,
Antoine Leca écrit:

En , Fabrice va escriure:

Si la norme ne suffit pas, pourriez-vous m'indiquer un sous-ensemble
de la norme pouvant garantir la portabilité ?


En général, on se pose la question inverse: quel est le sur-ensemble minimum
de la norme qui ne rompt pas (trop) la portabilité mais qui permet de faire
des choses intéressantes.


Le sous-ensemble est tout de même important, surtout quand on voit
que C99 casse des programmes C90 strictement conformes.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% validated (X)HTML - Acorn / RISC OS / ARM, free software, YP17,
Championnat International des Jeux Mathématiques et Logiques, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Laurent Wacrenier
Vincent Lefevre <vincent+ écrit:
Donc la sortie de putchar('a'); dépend de l'implémentation, car le code
de 'a' n'est pas le même avec toutes les implémentations.


C'est sensé renvoyer un 'a' dans le jeu de caractères des char du
compilateur, si tant est que la sortie standart existe. Ça renvoie
donc toujours la même chose, même si la sémantique peut changer selon
la sortie standard.

De même, la
sortie de putchar(65); dépend de l'implémentation, car le 65 correspond
à un caractère dépendant de l'implémentation.


Le 65 ne correspond même pas nessessairement à un caractère valide.

Avatar
Antoine Leca
En , Laurent Wacrenier va escriure:
Vincent Lefevre <vincent+ écrit:
Donc la sortie de putchar('a'); dépend de l'implémentation, car le
code de 'a' n'est pas le même avec toutes les implémentations.


C'est sensé renvoyer un 'a' dans le jeu de caractères des char du
compilateur,


Pas du compilateur, celui de l'hôte.
Celui du compilateur n'a rien à voir (sauf dans les expressions #if)

si tant est que la sortie standart existe. Ça renvoie
donc toujours la même chose, même si la sémantique peut changer selon
la sortie standard.


La sémantique sera la même, non ?

(Sauf si 'a' n'est pas "imprimable", mais là on rentre dans les sphères du
nîrvanâ théorique flou, sans aucun intérêt dans la pratique).


Antoine


Avatar
Laurent Wacrenier
Antoine Leca écrit:
C'est sensé renvoyer un 'a' dans le jeu de caractères des char du
compilateur,


Pas du compilateur, celui de l'hôte.
Celui du compilateur n'a rien à voir (sauf dans les expressions #if)


Essayez de compiler le code avec un compilateur completement ASCII et
d'executer le programme résultant sur un terminal EBCDIC branché sur
le même hôte.

Vous devriez obtenir de la bouillie.

Par contre, si le compilateur, tout en prenant le code en ASCII,
transcode les char constants en EBCDIC, le résultat sera présentable.

si tant est que la sortie standart existe. Ça renvoie
donc toujours la même chose, même si la sémantique peut changer selon
la sortie standard.


La sémantique sera la même, non ?

(Sauf si 'a' n'est pas "imprimable", mais là on rentre dans les sphères du
nîrvanâ théorique flou, sans aucun intérêt dans la pratique).


Ce que le lecteur verra sur la sortie standard ne sera pas
nessessairement un 'a'. Ce ne sera pas nessessairement un caractère
non plus (une séquence d'échapement, un bout de caractère, un groupe
de caractères, etc.)


1 2 3 4 5