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
Vincent Lefevre
Dans l'article ,
Fabrice écrit:

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 ?


Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.

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).


Rares sont les compilateurs respectant la norme et non buggé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.


Pour faire court, disons que la norme ne définit pas tout (cf les notions
de conforme vs strictement conforme, en particulier).

Concernant la portabilité, la norme C définit une machine virtuelle
paramétrée, avec en plus une possibilité de comportement indéfini.
Cela demande donc un effort supplémentaire au programmeur par rapport
à des langages qui spécifieraient absolument tout, indépendamment de
l'architecture (le Java s'y rapproche, par exemple).

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


Pas grand chose à part

int main(void)
{
return 0;
}

et encore, rien ne dit que l'exécution de ce programme ne provoquera
pas un débordement de pile ou autre dans la pratique.

--
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
Fabrice
On Fri, 9 Apr 2004 23:43:11 +0000 (UTC), Vincent Lefevre

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 ?


Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.


Pour les entrées/sorties on peut fonctionner avec des fichiers textes.
Nos programmes sont essentiellements des programmes effectuant des
calculs mathématiques. Il est facile de vérifier que les données en
entrées rentrent bien dans la norme (entiers bien compris entre -32767
et 32768 par exemple).


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).


Rares sont les compilateurs respectant la norme et non buggés.


Ah ? est-ce que tu aurais des exemples ? nous utilisons essentiellement
gcc par exemple.

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.


Pour faire court, disons que la norme ne définit pas tout (cf les
notions de conforme vs strictement conforme, en particulier).

Concernant la portabilité, la norme C définit une machine virtuelle
paramétrée, avec en plus une possibilité de comportement indéfini.
Cela demande donc un effort supplémentaire au programmeur par rapport
à des langages qui spécifieraient absolument tout, indépendamment de
l'architecture (le Java s'y rapproche, par exemple).


Nous essayons justement d'éviter tout comportement indéfini.
Mais il faut avouer que c'est relativement facile vu que nous ne
réalisons que des programmes avec de faibles entrées/sorties
(essentiellement des entiers/réels via des fichiers textes) et que les
fonctions que nous utilisons sont souvent relativement simples :
- fopen
- malloc
- cos, sin, atan...
- printf

Le plus gros des fonctions exotiques se trouvent d'ailleurs dans la
routine de lecture des fichiers (strtol, strpbrk, etc...).

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


Pas grand chose à part

int main(void)
{
return 0;
}

et encore, rien ne dit que l'exécution de ce programme ne provoquera
pas un débordement de pile ou autre dans la pratique.


Alors là vous m'inquiétez ! est-il réellement impossible de garantir
qu'un programme plus compliqué sera portable ?


Avatar
Vincent Lefevre
Dans l'article ,
Fabrice écrit:

On Fri, 9 Apr 2004 23:43:11 +0000 (UTC), Vincent Lefevre

Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.


Pour les entrées/sorties on peut fonctionner avec des fichiers textes.


Même avec les fichiers texte. La norme dit:

[#5] A strictly conforming program shall use only those
features of the language and library specified in this
International Standard.2) It shall not produce output
dependent on any unspecified, undefined, or implementation-
defined behavior, and shall not exceed any minimum
implementation limit.

Or le codage des caractères dépend de l'implémentation (ce n'est pas
forcément à base d'ASCII, tu as des implémentations en EBCDIC, par
exemple).

Nos programmes sont essentiellements des programmes effectuant des
calculs mathématiques. Il est facile de vérifier que les données en
entrées rentrent bien dans la norme (entiers bien compris entre -32767
et 32768 par exemple).


-32767 et 32767.

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).


Rares sont les compilateurs respectant la norme et non buggés.


Ah ? est-ce que tu aurais des exemples ? nous utilisons essentiellement
gcc par exemple.


Bon, gcc est peut-être censé suivre la norme C90, mais il y a des bugs.
Et n'utilise surtout pas Gnu Pro. :)

Nous essayons justement d'éviter tout comportement indéfini.
Mais il faut avouer que c'est relativement facile vu que nous ne
réalisons que des programmes avec de faibles entrées/sorties
(essentiellement des entiers/réels via des fichiers textes) et que les
fonctions que nous utilisons sont souvent relativement simples :
- fopen
- malloc
- cos, sin, atan...
- printf


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). Même avec ça, tu as des bugs liés à la
précision étendue sur certaines archi (e.g. Linux/x86), sauf à utiliser
-ffloat-store. Et rien n'est spécifié concernant les fonctions
transcendantes (cos, sin, atan...). Avec les fonctions génériques de
la glibc (utilisée sur PowerPC, par exemple), si on se place en arrondi
dirigé, on peut même faire planter le programme. :)

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

Concernant les flottants, il y a (a eu) pas mal de bugs dans la
glibc. Concernant les bugs que j'ai rapportés:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug7020
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug3022
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug3548
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug2574
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!0400
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!0613
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!6800
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug"6291

Alors là vous m'inquiétez ! est-il réellement impossible de garantir
qu'un programme plus compliqué sera portable ?


La portabilité est tout relative. En général, on suppose tout de même
que l'implémentation se comporte de manière "raisonnable".

--
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
Fabrice
On Sat, 10 Apr 2004 00:34:21 +0000 (UTC), Vincent Lefevre

Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.


Pour les entrées/sorties on peut fonctionner avec des fichiers
textes.


Même avec les fichiers texte. La norme dit:

[#5] A strictly conforming program shall use only those
features of the language and library specified in this
International Standard.2) It shall not produce output
dependent on any unspecified, undefined, or implementation-
defined behavior, and shall not exceed any minimum
implementation limit.

Or le codage des caractères dépend de l'implémentation (ce n'est pas
forcément à base d'ASCII, tu as des implémentations en EBCDIC, par
exemple).


Argh ! Flûte ! je n'avais pas pensé à ça...

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).


Rares sont les compilateurs respectant la norme et non buggés.


Ah ? est-ce que tu aurais des exemples ? nous utilisons
essentiellement gcc par exemple.


Bon, gcc est peut-être censé suivre la norme C90, mais il y a des
bugs. Et n'utilise surtout pas Gnu Pro. :)


Oui, oui c'est pour ça que j'avais précisé "aux bugs du compilateur
près". Aucun programme n'est -hélas !- parfait...

Nous essayons justement d'éviter tout comportement indéfini.
Mais il faut avouer que c'est relativement facile vu que nous ne
réalisons que des programmes avec de faibles entrées/sorties
(essentiellement des entiers/réels via des fichiers textes) et que
les fonctions que nous utilisons sont souvent relativement simples :
- fopen
- malloc
- cos, sin, atan...
- printf


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). Même avec ça, tu as des bugs liés à
la précision étendue sur certaines archi (e.g. Linux/x86), sauf à
utiliser-ffloat-store. Et rien n'est spécifié concernant les fonctions
transcendantes (cos, sin, atan...). Avec les fonctions génériques de
la glibc (utilisée sur PowerPC, par exemple), si on se place en
arrondi dirigé, on peut même faire planter le programme. :)


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 ?
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) ?

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 ? (hormis les
problèmes de codage de caractères ! j'avais oublié ça...)


Concernant les flottants, il y a (a eu) pas mal de bugs dans la
glibc. Concernant les bugs que j'ai rapportés:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug7020
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug3022
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug3548
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug2574
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!0400
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!0613
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug!6800
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug"6291


Ah ! Un utilisateur de Debian ? Très bonne distribution ça ! ;-)

Alors là vous m'inquiétez ! est-il réellement impossible de garantir
qu'un programme plus compliqué sera portable ?


La portabilité est tout relative. En général, on suppose tout de même
que l'implémentation se comporte de manière "raisonnable".


Bon du coup je suis un peu perdu là (il est grand temps d'aller dormir
!), que dois-je répondre à mon collègue ?

- "Un programme codé en ISO C90 est-il portable ?"
- "ça dépend de ce que l'on entend par portabilité, de manière stricte
ce n'est pas vrai par contre en général c'est plus ou moins vrai"




Avatar
Jean-Marc
"Fabrice" a écrit dans le message de
news:
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.


Hello,
nous produisons des programmes en C, qui tournent en production
24h/24h, 7j/7j, dans de grandes banques. Nos programmes, écrit
dans un strict respect de la norme, compilent et s'éxécutent sur NT,
Linux, IBM AIX, SUN solaris, HP, VAX VMS et sur mainframe IBM, sous
OS 390 et sous Z/Os (ici nous sommes en EBCDIC). Nous faisons
énormémen d'entrés sorties (et pas seulement en texte, en binaire aussi)
et le source des programmes est le même pour chaque client/plateforme.
Evidemmment, nous avons dans les headers quelques directives de
compilation ou d'inclusion conditionnelle. Par exemple, pour désigner
le retour chariot, tous les modules utilisent la constante HEXA_CR,
et celle ci est définie dans un .h avec la valeur adéquate en fonction de
la plateforme.

Pour les entrés sorties, y compris en binaire, tout va bien tant que les
données
sont écrites et lues sur la même plateforme.

La réponse est donc oui, un programme écrit convenablement, qui ne fait pas
de présuppositions sur tel ou tel comportement dans les cas non définis par
la norme
fonctionne sur n'importe quel OS, en tout cas sur ceux que je viens de
nommer.

Jean-Marc

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

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 ?


Ca aide, mais ce n'est pas garanti.

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).


Si le comportement est défini par la norme, oui.

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.


Le problème est que beaucoup de choses ne sont pas définies par la norme
(comportements indéfinis), ce qui peut entrainer un tas de dysfonctionnements
même si on suit la norme à la lettre. Exemple:

#include <stdio.h>
int main (void)
{
char *s = "Hello world";

s[4] = 'x';
return 0;
}

Ce code est parfaitement 'légal' (il ne brise aucune regle écrite), mais il
invoque un comportement indéfini (une chaine littérale pourrait très bien
être non modifiable), ce qui est un bug (potentiel ou avéré).

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


Si on s'en tient strictement à ce qui est défini, c'est bon.

--
-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', Vincent Lefevre <vincent+ wrote:

Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.


Ah? On a retiré <stdio.h> de la norme? Je ne savais pas.

--
-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', Fabrice wrote:

et encore, rien ne dit que l'exécution de ce programme ne provoquera
pas un débordement de pile ou autre dans la pratique.


Alors là vous m'inquiétez ! est-il réellement impossible de garantir
qu'un programme plus compliqué sera portable ?


La remarque de Vincent est tout à fait pertinente. Un usage abusif des
variables locales ou de la recursivité ou un trop grande nombre d'appels
imbriqués peuvent entrainer un comportement indéfini. Il y a quelques
minimums garantis, mais qui les contrôle?

Exemple réel.

J'ai travaillé longtemps sur une plateforme à base de mircrocontrôleur
Motorola 68302 (coeur 68000 + memoire interne + périphériques orienté
telecom).

Au démarrage, la mémoire externe n'est pas accessible. La pile utilisée est
prise sur une petite zone de mémoire interne de (User Data Memory) de 240
octets, c'est à dire pas grand chose. Et bien avec une telle pile, un simple
appel à sprintf() est impossible (explosition!). Il a donc fallu que j'écrive
mes fonctions de conversion num/text pour pouvoir afficher le resultat de
l'autotest et autres joyeusetés.

--
-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
Vincent Lefevre
Dans l'article ,
Fabrice écrit:

On Sat, 10 Apr 2004 00:34:21 +0000 (UTC), Vincent Lefevre

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). Même avec ça, tu as des bugs liés à
la précision étendue sur certaines archi (e.g. Linux/x86), sauf à
utiliser-ffloat-store. Et rien n'est spécifié concernant les fonctions
transcendantes (cos, sin, atan...). Avec les fonctions génériques de
la glibc (utilisée sur PowerPC, par exemple), si on se place en
arrondi dirigé, on peut même faire planter le programme. :)


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 ?


Un bug de la bibliothèque C. C'est essentiellement pour signaler qu'ils
existent en pratique.

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) ?


Sauf bug, oui. Enfin... la norme C n'impose pas une précision (au sens
"accuracy") minimale il me semble.

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 ? (hormis les
problèmes de codage de caractères ! j'avais oublié ça...)


Oui, aux erreurs d'arrondi près. Même problème que pour cos.

La portabilité est tout relative. En général, on suppose tout de même
que l'implémentation se comporte de manière "raisonnable".


Bon du coup je suis un peu perdu là (il est grand temps d'aller dormir
!), que dois-je répondre à mon collègue ?

- "Un programme codé en ISO C90 est-il portable ?"


S'il évite les comportements indéfinis et dépendants de l'implémentation,
oui, au sens de la norme. Mais cela ne veut pas dire qu'il n'y aura pas
de problème en pratique, à cause de bugs de compilo, etc.

Il ne faut pas non plus qu'il écrive quelque chose du genre a//**/b,
car ça ne passe pas en C99. Mais bon, ça m'étonnerait qu'on écrive ce
genre de choses habituellement...

--
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 ,
Emmanuel Delahaye écrit:

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

Si tu suis strictement la norme, tu ne peux pas faire grand chose,
en particulier aucune entrée-sortie.


Ah? On a retiré <stdio.h> de la norme? Je ne savais pas.


Avec la notion de *strictement* conforme, tu ne dois pas générer de
sortie qui dépende 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


1 2 3 4 5