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

3 4 5 6 7
Avatar
Éric Lévénez
Le 13/04/04 22:50, dans , « Laurent
Wacrenier » <lwa@ teaser . fr> a écrit :

Éric Lévénez écrit:
Tout dépend de ce que l'on appelle "interne" d'unix. Par exemple sur Mac OS
X, qui est un unix, l'interface des fichiers doit utiliser des caractères en
UTF-8 (Unicode 4 sous Panther). L'utilisation d'un nom de fichier avec une
séquence de char 8 bits non conforme UTF-8 retourne une erreur,
contrairement aux autres unix.


Je ne connais pas MacOS, mais ça semble être une fonctionalité du


C'est Mac OS X, pas Mac OS. Ce n'est pas le même système d'exploitation.
Mac OS ce sont des versions du type 8, 9... et Mac OS X ce sont des versions
du genre 10.0, 10.3...

système de fichiers. Sur un autre système de fichier du même OS (par
exemple, un ISO9960 pour les CD), le jeu de caractère peut être
différent.


L'UTF-8 est utilisé au niveau du VFS. C'est seulement dans les couches plus
basses que les caractères sont adaptés au file-system selon ce qu'il sait
gérer. Par exemple l'ISO 9660 avec son extension Joliet ne gère pas tout
l'Unicode 4 et des coupes/adaptations sont à faire.

L'interface d'affichage dépend, elle, de
l'émulation choisie dans Terminal, qui est par défaut UTF-8.



--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
Antoine Leca
En , Laurent Wacrenier va escriure:
La représenation sur un système du char imprimable 'a' sur un
autre système n'est pas nessessairement un caractère imprimable,


Qui a dit que c'était ce qui se passait ?
Depuis quand isprint() est une constante ?

ni même un caractère.


Pardon ?
'a' est *toujours* un caractère. Par définition, un caractère est ce qui
rentre dans un multiplet (byte en anglais), et 'a' doit être représentable
(et en plus avoir une valeur positive).

Sauf bien sûr si on parle pas de C, mais ce serait gentil de le préciser
avant.

Antoine

Avatar
Antoine Leca
En 20040413182354$, Vincent Lefevre va escriure:
Dans l'article <c5h988$hcv$,
Antoine Leca écrit:

En 20040413163318$, Vincent Lefevre va escriure:
C'est sensé renvoyer un 'a' dans le jeu de caractères des char du
compilateur,


Pas du compilateur, celui de l'hôte.


C'est plus lié au compilateur (en fait à l'ensemble de
l'environnement).


?

Le jeu de caractère de l'environnement, c'est celui de l'hôte.


Le jeu de caractères n'est pas lié à l'hôte, mais au processus


1) Je n'ai jamais écrit écrit que l'hôte était différent d'un processus.
2) En quoi cette « liaison » justifie-t-elle un tant soit peu l'affirmation
que ce n'est pas lié à l'environnement d'exécution (l'hôte), mais bien
plutôt le compilateur ?

(comme l'ensemble des locales).


De quelles locales parle-t-on ? Des locales POSIX ? Que viennent-elles faire
ici ?
S'il s'agit de la locale C, alors c'est plus que très clairement un concept
d'exécution, rien à voir avec la compilation.

Dans le cas d'une compilation,
le processus est le compilateur (enfin, il peut y avoir plusieurs
processus, mais je suppose qu'il n'y aura pas de changement de
jeu de caractères à ce niveau).


Mais pourquoi diantre le compilateur devrait être dans un système comparable
à l'environnement d'exécution ? Pourquoi devrait-ce être un processus ?
Est-ce que tu veux obliger le compilateur à être lui-même un un programme C
?


Imagine donc un compilateur *nix qui fonctionne avec comme jeu de
caractère interne, Unicode (parfaitement vraissemblable aujourd'hui,
non).


C'est invraissemblable avec des char sur 8 bits (cas de la majorité
des *nix -- enfin je ne connais aucun *nix où ça ne peut être
autrement). Sinon, que signifie

putchar('é');

avec Unicode comme jeu de caractères?


Jeu de caractères : ensemble des entités indépendantes.

Tu confonds ici avec la représentation, ce qui avec les jeux de caractères
de grande dimension (Asie orientale, ou Unicode) pose un problème pour
rentrer dans la limite des 8 bits imposée par les architectures techniques.
D'où les "multibytes", wchar_t et autres joyeusetés, et le résultat que de
plus en plus les "caractères" (les éléments du jeu) doivent être manipulés
avec des chaînes, même quand ils sont unitaires.

Dans la norme C, il y a une distinction très claire entre le jeu de
caractères de base (dont 'a'), qui est obligé d'être encodé dans un char; et
les caractères étendus, dont par exemple 'é', qui pour être représenté peut
nécessiter plusieurs octets (un seul 0xE9 avec iso-8859-1, mais deux
0xA8,0xA6 en EUC-CN ou 0xC3,0xA9 en utf-8; et même trois 0x8F,0xAB,0xB1 en
EUC-JP)


Je parlais de la locale utilisée pour la compilation


Mais qu'est ce que cela a à voir ?
Reprenons mon exemple d'un compilateur croisé opérant sur une machine ASCII
qui produit du code pour une machine EBCDIC. En quoi le codage à l'intérieur
du compilateur peut-il avoir la moindre influence sur ce qui est émis dans
le binaire ? En fait, si cela devait avoir la moindre influence, on aurait
de grois problèmes, ne crois-tu pas ?

Bon l'exemple est extrême, mais il devrait aider à comprendre le sujet. Et
en plus, ce n'est pas un exemple théorique, ce genre de bestiau existe.


et non pas
pour le lancement du programme (bien qu'en pratique, il me semble
qu'il vaille mieux que ce soient des locales compatibles si des
caractères non ASCII sont en dur dans le source).


Non non. Par exemple, je crois que le compilo C (ou C# ?) de Microsoft est
capable de lire des fichiers UTF-16 (en tous cas, certains outils de
développement le sont). Mais le code produira des caractères et des chaînes
codées avec une "page de codes" à préciser, sur une base de 8 bits, sauf si
tu précises que tu veux des wchar_t (L'é'), auquel cas tu obtiens de
l'UTF-16. Dans le sens contraire, le compilateur javac ne sait lire
(crois-je) que du 8 bits, peut-être UTF-8, mais en sortie il ne sait émettre
que de l'UTF-16, contrainte de la plateforme JVM oblige.


Antoine





Avatar
Laurent Wacrenier
Antoine Leca écrit:
En , Laurent Wacrenier va escriure:
La représenation sur un système du char imprimable 'a' sur un
autre système n'est pas nessessairement un caractère imprimable,


Qui a dit que c'était ce qui se passait ?
Depuis quand isprint() est une constante ?

ni même un caractère.


Pardon ?
'a' est *toujours* un caractère. Par définition, un caractère est ce qui
rentre dans un multiplet (byte en anglais), et 'a' doit être représentable
(et en plus avoir une valeur positive).


Ce ne sera pas nessessairement un caractère pour le lecteur de la
sortie standard.


Avatar
Vincent Lefevre
Dans l'article <c5irn2$6b0$,
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.


C'est plus lié au compilateur (en fait à l'ensemble de
l'environnement).


?

Le jeu de caractère de l'environnement, c'est celui de l'hôte.


Le jeu de caractères n'est pas lié à l'hôte, mais au processus


1) Je n'ai jamais écrit écrit que l'hôte était différent d'un processus.


L'hôte est lié à l'exécution, alors qu'ici on parle de compilation.

2) En quoi cette « liaison » justifie-t-elle un tant soit peu l'affirmation
que ce n'est pas lié à l'environnement d'exécution (l'hôte), mais bien
plutôt le compilateur ?


Parce que quand on compile, les constantes du source comme 'a' ou 'é'
sont stockées en dur dans le code généré. Si on exécute ce code dans
un environnement ayant un jeu de caractères différent (c'est facile
à changer sous Unix), on obtiendra un résultat différent (concernant
les caractères, pas les codes eux-mêmes). Les constantes caractère du
source sont bien liées à l'environnement de compilation et non pas à
l'environnement d'exécution.

(comme l'ensemble des locales).


De quelles locales parle-t-on ? Des locales POSIX ? Que
viennent-elles faire ici ?


Les locales définissant l'environnement du compilateur (dans le
contexte d'une compilation, évidemment).

Dans le cas d'une compilation, le processus est le compilateur
(enfin, il peut y avoir plusieurs processus, mais je suppose qu'il
n'y aura pas de changement de jeu de caractères à ce niveau).


Mais pourquoi diantre le compilateur devrait être dans un système
comparable à l'environnement d'exécution ? Pourquoi devrait-ce être
un processus ? Est-ce que tu veux obliger le compilateur à être
lui-même un un programme C ?


Non, mais c'est le cas pratique. Si on veut considérer le cas général,
on ne devrait pas parler de compilateur. Remplace ce qu'il y a
ci-dessus par traducteur, si tu veux...

Imagine donc un compilateur *nix qui fonctionne avec comme jeu de
caractère interne, Unicode (parfaitement vraissemblable aujourd'hui,
non).


C'est invraissemblable avec des char sur 8 bits (cas de la majorité
des *nix -- enfin je ne connais aucun *nix où ça ne peut être
autrement). Sinon, que signifie

putchar('é');

avec Unicode comme jeu de caractères?


Jeu de caractères : ensemble des entités indépendantes.

Tu confonds ici avec la représentation,


Je n'ai pas parlé de représentation, juste du jeu de caractères
(Unicode) et de la taille des char (8 bits dans mon exemple).
Quelle que soit l'encodage (UTF-8, UTF-16...), je ne vois pas
comment ça peut tenir.

Dans la norme C, il y a une distinction très claire entre le jeu de
caractères de base (dont 'a'), qui est obligé d'être encodé dans un
char; et les caractères étendus, dont par exemple 'é', qui pour être
représenté peut nécessiter plusieurs octets (un seul 0xE9 avec
iso-8859-1, mais deux 0xA8,0xA6 en EUC-CN ou 0xC3,0xA9 en utf-8; et
même trois 0x8F,0xAB,0xB1 en EUC-JP)


Quand tu disais "comme jeu de caractère interne, Unicode", j'avais
supposé que tu parlais du jeu de caractères de base. Parce que le
jeu de caractères étendu est peu (ou pas du tout) utilisé sous Unix.

Je parlais de la locale utilisée pour la compilation


Mais qu'est ce que cela a à voir ?


Cf ci-dessus.

Reprenons mon exemple d'un compilateur croisé opérant sur une
machine ASCII qui produit du code pour une machine EBCDIC. En quoi
le codage à l'intérieur du compilateur peut-il avoir la moindre
influence sur ce qui est émis dans le binaire ? En fait, si cela
devait avoir la moindre influence, on aurait de grois problèmes, ne
crois-tu pas ?


Mauvais exemple, changer d'exemple. Il y a problème quand le jeu de
caractères de l'environnement d'exécution n'est pas fixe.

et non pas pour le lancement du programme (bien qu'en pratique, il
me semble qu'il vaille mieux que ce soient des locales compatibles
si des caractères non ASCII sont en dur dans le source).


Non non. Par exemple, je crois que le compilo C (ou C# ?) de
Microsoft est capable de lire des fichiers UTF-16 (en tous cas,
certains outils de développement le sont). Mais le code produira des
caractères et des chaînes codées avec une "page de codes" à
préciser, sur une base de 8 bits, sauf si tu précises que tu veux
des wchar_t (L'é'), auquel cas tu obtiens de l'UTF-16.


Tu peux le préciser à l'exécution?

--
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
Antoine Leca
En , Laurent Wacrenier va escriure:
Ce ne sera pas nessessairement un caractère pour le lecteur de la
sortie standard.


Alors vous êtes sorti du cadre de la norme. Celle-ci ne s'occupe pas de
normaliser l'utilisation des sorties (ni celle des entrées, d'ailleurs).


Antoine

Avatar
Antoine Leca
En 20040414125859$, Vincent Lefevre va escriure:
1) Je n'ai jamais écrit écrit que l'hôte était différent d'un
processus.


L'hôte est lié à l'exécution, alors qu'ici on parle de compilation.


Mais qui parle de compilation ? Le sujet traite de la norme C90 et de ses
lacunes. Cette norme s'occupe de définir l'effet des programmes
(l'exécution), et pas de savoir comment (algorithmes, performances, causes,
formats, etc.) se fait la translation, autrement dit ne s'occupe absolument
pas de la compilation.


2) En quoi cette « liaison » justifie-t-elle un tant soit peu
l'affirmation que ce n'est pas lié à l'environnement d'exécution
(l'hôte), mais bien plutôt le compilateur ?


Parce que quand on compile, les constantes du source comme 'a' ou 'é'
sont stockées en dur dans le code généré.


Oui. Ces valeurs sont d'ailleurs celles dans le jeu de caractères
d'exécution. Phase 5 du modèle (5.1.1.2). Le jeu source n'a aucune
importance ici.

Et oui, le compilateur doit connaître le jeu d'exécution. En fait, il doit
même le documenter: 5.2.1p1 "The values of the members of the execution
character set are implementation-defined."


Si on exécute ce code dans
un environnement ayant un jeu de caractères différent (c'est facile
à changer sous Unix),


Non.
D'abord, un 'a' est toujours un 'a'.

Ensuite, si tu changes de locale (ce qui toujours un acte volontaire, il
faut appeler setlocale()) sans tenir compte des encodages, tu invoques un
comportement dépendant de la locale. Si ton programme agit différement dans
ces cas-là, il n'est plus strictement conforme, et encore une fois on est
sorti du propos de cette enfilade.


on obtiendra un résultat différent (concernant
les caractères, pas les codes eux-mêmes). Les constantes caractère du
source sont bien liées à l'environnement de compilation et non pas à
l'environnement d'exécution.


Mais cela n'a rien à voir. On peut parfaitement avoir un compilateur *nix
qui accepte en paramètre la locale d'encodage des caractères. Ce sera la
manière utilisée pour encoder le binaire, autrement dit le jeu d'exécution.

Et ce n'est pas lié au source, qui peut être sans problème dans un autre jeu
de caractère (par exemple, le LC_CTYPE/LANG/LC_ALL de l'environnement dans
lequel a été lancé le processus c89, selon POSIX.2). Ce dernier jeu est
celui qui est évoqué en phase 1, "Physical source file multibyte characters
are mapped, in an implementation-defined manner, to the source character
set". Un compilateur multilangue pourrait donc parfaitement utiliser Unicode
comme jeu de caractère source (avec l'encodage que l'on veut, UTF-8 ou -16
ou -32), lisant des sources encodés comme l'on veut suivant LC_xxx, et
produisant des objet encodés d'une autre façon en fonction d'un paramètre
passé en option de ligne de commandes. Le modèle est fait pour cela.



De quelles locales parle-t-on ? Des locales POSIX ? Que
viennent-elles faire ici ?


Les locales définissant l'environnement du compilateur (dans le
contexte d'une compilation, évidemment).


Elles affectent logiquement la lecture du source, mais n'ont pas de raison
d'affecter aussi celle du binaire. Ou du moins, ce ne sont pas forcément les
mêmes: le développeur n'est pas obligé de changer de locale pour coller à
celle de chacun de ses clients: il reste dans la sienne.



Imagine donc un compilateur *nix qui fonctionne avec comme jeu de
caractère interne, Unicode (parfaitement vraissemblable
aujourd'hui, non).


C'est invraissemblable avec des char sur 8 bits (cas de la majorité
des *nix -- enfin je ne connais aucun *nix où ça ne peut être
autrement). Sinon, que signifie

putchar('é');

avec Unicode comme jeu de caractères?


Jeu de caractères : ensemble des entités indépendantes.

Tu confonds ici avec la représentation,


Je n'ai pas parlé de représentation, juste du jeu de caractères
(Unicode) et de la taille des char (8 bits dans mon exemple).
Quelle que soit l'encodage (UTF-8, UTF-16...), je ne vois pas
comment ça peut tenir.


Sans problèmes: une constante comme 'é' est un entier en C, pas un char.
Maintenant, c'est sûr que le putchar ci-dessus ne va pas avoir l'effet prévu
(et ce, sans que tu sois prévenu): une raison de plus pour ne pas faire
cela.



Dans la norme C, il y a une distinction très claire entre le jeu de
caractères de base (dont 'a'), qui est obligé d'être encodé dans un
char; et les caractères étendus, dont par exemple 'é', qui pour être
représenté peut nécessiter plusieurs octets (un seul 0xE9 avec
iso-8859-1, mais deux 0xA8,0xA6 en EUC-CN ou 0xC3,0xA9 en utf-8; et
même trois 0x8F,0xAB,0xB1 en EUC-JP)


Quand tu disais "comme jeu de caractère interne, Unicode", j'avais
supposé que tu parlais du jeu de caractères de base. Parce que le
jeu de caractères étendu est peu (ou pas du tout) utilisé sous Unix.


Cf. supra pour une des raisons.

En fait, le jeu de caractères de base, c'est ASCII sauf $ @ ` (c'est un
point qui a été éclairci en C99).
Ce que tu veux dire, c'est « les caractères représentés sur un seul octet ».
Ce qui est différent.


Reprenons mon exemple d'un compilateur croisé opérant sur une
machine ASCII qui produit du code pour une machine EBCDIC. En quoi
le codage à l'intérieur du compilateur peut-il avoir la moindre
influence sur ce qui est émis dans le binaire ? En fait, si cela
devait avoir la moindre influence, on aurait de grois problèmes, ne
crois-tu pas ?


Mauvais exemple, changer d'exemple. Il y a problème quand le jeu de
caractères de l'environnement d'exécution n'est pas fixe.


EBCDIC est un exemple typique d'enviroennemnt où les jeux de caractères à
l'exécution ne sont *PAS* fixes ;-).



et non pas pour le lancement du programme (bien qu'en pratique, il
me semble qu'il vaille mieux que ce soient des locales compatibles
si des caractères non ASCII sont en dur dans le source).


Non non. Par exemple, je crois que le compilo C (ou C# ?) de
Microsoft est capable de lire des fichiers UTF-16 (en tous cas,
certains outils de développement le sont). Mais le code produira des
caractères et des chaînes codées avec une "page de codes" à
préciser, sur une base de 8 bits, sauf si tu précises que tu veux
des wchar_t (L'é'), auquel cas tu obtiens de l'UTF-16.


Tu peux le préciser à l'exécution?


Non, cf. supra. Tu dois préciser cela à la compilation. C'est une des
limites du modèle du C, par opposition aux langages plus récents de Ada à
HTML, en passant par les descriptions de ressources, qui adoptent Unicode
comme seul jeu, avec un paramètre réglable _à l'exécution_ pour choisir la
représentation; à l'intérieur du binaire, tu as toujours un certains
encodage de Unicode.

En C, on devrait avoir le même effet avec MSE (les wchar_t, wcs*() etc.),
mais de la manière dont cela a été spécifié, cela n'est pas toujours vrai,
ce qui fait que ce modèle n'est pas intéressant dans la pratique.


Antoine




Avatar
Vincent Lefevre
Dans l'article <c5k1e7$6hs$,
Antoine Leca écrit:

En 20040414125859$, Vincent Lefevre va escriure:
1) Je n'ai jamais écrit écrit que l'hôte était différent d'un
processus.


L'hôte est lié à l'exécution, alors qu'ici on parle de compilation.


Mais qui parle de compilation ? Le sujet traite de la norme C90 et de ses
lacunes.


Le message d'origine de Fabrice (ainsi que les suivants) parle du
résultat de la compilation. Faut suivre!

2) En quoi cette « liaison » justifie-t-elle un tant soit peu
l'affirmation que ce n'est pas lié à l'environnement d'exécution
(l'hôte), mais bien plutôt le compilateur ?


Parce que quand on compile, les constantes du source comme 'a' ou 'é'
sont stockées en dur dans le code généré.


Oui. Ces valeurs sont d'ailleurs celles dans le jeu de caractères
d'exécution.


qui n'est pas forcément défini à l'avance, dans la pratique.

Phase 5 du modèle (5.1.1.2). Le jeu source n'a aucune importance
ici.


Mais je ne parle pas du jeu source, seulement du fait qu'il y a des
constantes de caractère dans le source.

Et oui, le compilateur doit connaître le jeu d'exécution.


Ce n'est pas le cas en pratique.

Si on exécute ce code dans un environnement ayant un jeu de
caractères différent (c'est facile à changer sous Unix),


Non.
D'abord, un 'a' est toujours un 'a'.


Ça ne veut rien dire.

Ensuite, si tu changes de locale (ce qui toujours un acte volontaire, il
faut appeler setlocale()) sans tenir compte des encodages, tu invoques un
comportement dépendant de la locale. Si ton programme agit différement dans
ces cas-là, il n'est plus strictement conforme, et encore une fois on est
sorti du propos de cette enfilade.


Mais c'est bien ce que je disais ici: <20040410000611$.

on obtiendra un résultat différent (concernant les caractères, pas
les codes eux-mêmes). Les constantes caractère du source sont bien
liées à l'environnement de compilation et non pas à
l'environnement d'exécution.


Mais cela n'a rien à voir. On peut parfaitement avoir un compilateur
*nix qui accepte en paramètre la locale d'encodage des caractères.
Ce sera la manière utilisée pour encoder le binaire, autrement dit
le jeu d'exécution.


Mais ce n'est pas ce qui se passe avec gcc par exemple.

Sans problèmes: une constante comme 'é' est un entier en C, pas un char.


Le problème venait de la confusion entre jeu de caractères de base
et jeu étendu (cf ci-dessous):

En fait, le jeu de caractères de base, c'est ASCII sauf $ @ ` (c'est un
point qui a été éclairci en C99).


Ça a changé par rapport au draft WG14/N869 alors (je ne le savais
pas); N869 dit seulement "at least".

Mauvais exemple, changer d'exemple. Il y a problème quand le jeu de
caractères de l'environnement d'exécution n'est pas fixe.


EBCDIC est un exemple typique d'enviroennemnt où les jeux de caractères à
l'exécution ne sont *PAS* fixes ;-).


Peut-être que ça fonctionne avec EBCDIC alors. Mais pas avec les
locales sous Unix par exemple, où changer de locale à l'exécution
peut mener à des problèmes.

--
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
Antoine Leca
En 20040414205844$, Vincent Lefevre va escriure:
Mais qui parle de compilation ? Le sujet traite de la norme C90 et
de ses lacunes.


Le message d'origine de Fabrice (ainsi que les suivants) parle du
résultat de la compilation. Faut suivre!


On ne doit pas avoir la même manière de lire...

Je cite:

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

« N'importe quel compilateur », c'est clairement à mon sens l'obligation de
ne pas dépendre du compilateur. Donc de ne pas s'intéresser aux
particularités de tel ou tel.

La question est très semblable à la démarche adoptée par la norme (tellement
que cela m'en a paru suspect). Tandis que la discussion que nous avons
maintenant, sur les compilos *nix et les locales, n'y est pas directement
lié, àmha.



Parce que quand on compile, les constantes du source comme 'a' ou
'é' sont stockées en dur dans le code généré.


Oui. Ces valeurs sont d'ailleurs celles dans le jeu de caractères
d'exécution.


qui n'est pas forcément défini à l'avance, dans la pratique.


Je ne sais pas de quelle pratique tu parles.

Dans la norme, c'est tellement défini à l'avance que cela l'est avant même
le début de la compilation: ce codage est « défini par l'implémentation »,
ce qui signifie que le fournisseur du compilateur est obligé de le préciser
dans la documentation.


Phase 5 du modèle (5.1.1.2). Le jeu source n'a aucune importance
ici.


Mais je ne parle pas du jeu source, seulement du fait qu'il y a des
constantes de caractère dans le source.


Oui, moi aussi. Et les constantes de caractères dans le source, dans les pha
ses 1-4 sont exprimés dans le jeu source, et dans les phases 6-8 dans le jeu
exécution. Comme le binaire c'est le résultat de la phase 8...


Si on exécute ce code dans un environnement ayant un jeu de
caractères différent (c'est facile à changer sous Unix),


Non.
D'abord, un 'a' est toujours un 'a'.


Ça ne veut rien dire.


Cela veut dire que avec *nix, tu peux changer autant que tu veux l'encodage
de 'é'. Mais pas celui de 'a'. Tant la norme C ISO que POSIX oblige à ce que
'a' signifie toujours la même chose, la même valeur (avec une limite de
périmètre, évidemment: ce périmètre est flou en C, mais il est un peu plus
défini en POSIX: au début c'était une machine, maintenqant c'est un peu plus
large, et probablement que dans un futur pas trop lointain on aura
l'obligation d'utiliser ASCII ou au moins un dérivé de ISO 646; POSIX-2001 a
déjà obligé CHAR_BIT à être égal à 8, ce qui n'était pas formellement obligé
auparavant).


Ensuite, si tu changes de locale (ce qui toujours un acte
volontaire, il faut appeler setlocale()) sans tenir compte des
encodages, tu invoques un comportement dépendant de la locale. Si
ton programme agit différement dans ces cas-là, il n'est plus
strictement conforme, et encore une fois on est sorti du propos de
cette enfilade.


Mais c'est bien ce que je disais ici:
<20040410000611$.


Pas tout-à-fait.

Ce que disait, c'était
: > Pour les entrées/sorties on peut fonctionner avec des fichiers textes.
:
: Même avec les fichiers texte. La norme dit:
[couic citation clause 4, paragraphe 5]
: 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).

[Merci alphanet]

Or ici, je fais clairement la distinction entre les caractères du jeu de
base (comme 'a'), qui ne change pas à l'exécution et donc peuvent entrer
dans des programmes strictement conformes, et les caractères comme 'é' qui
ne le peuvent pas. Autrement dit, l'archétype HelloWorld.c est strictement
conforme.


on obtiendra un résultat différent (concernant les caractères, pas
les codes eux-mêmes). Les constantes caractère du source sont bien
liées à l'environnement de compilation et non pas à
l'environnement d'exécution.


Mais cela n'a rien à voir. On peut parfaitement avoir un compilateur
*nix qui accepte en paramètre la locale d'encodage des caractères.
Ce sera la manière utilisée pour encoder le binaire, autrement dit
le jeu d'exécution.


Mais ce n'est pas ce qui se passe avec gcc par exemple.


Non. Et alors ?
GCC C est un compilateur qui a des objectifs, entre autre portabilité sur le
maximum de plateformes, et possibilité de compilation croisée. Cela impose
certains choix, en l'occurence une architecture assez ouverte, donc plutôt
indépendantes des « contingences matérielles ». De ce fait il ne remplit pas
certaines fonctionnalités pointues; et pour les programmeurs anglophones, le
codage des caractères non-ASCII, ce n'est manifestement pas une priorité.


En fait, le jeu de caractères de base, c'est ASCII sauf $ @ ` (c'est
un point qui a été éclairci en C99).


Ça a changé par rapport au draft WG14/N869 alors (je ne le savais
pas); N869 dit seulement "at least".


Après vérification, oui.
Bizarre, je me souvenais bien de cette modification, on en avait parlé à
Copenhague (juin 98), mais j'aurais cru que cela avait été écrit plus tôt
que N877 (mars 99) dans le texte de la norme (N869 est daté janvier 99). On
a beaucoup acceléré le développement à ce moment-là, pour ne pas devenir C00
!

Le nouveau (et définitif) texte est:
5.2 Environmental considerations

5.2.1 Character sets

[1] Two sets of characters and their associated collating sequences shall be
defined: the set in which source files are written (the /source character
set/), and the set interpreted in the execution environment (the /execution
character set/). Each set is further divided into a /basic character set/,
whose contents are given by this subclause, and a set of zero or more
locale-specific members (which are not members of the basic character set)
called /extended characters/. The combined set is also called the /extended
character set/. The values of the members of the execution character set are
implementation-defined.

[2] In a character constant or string literal, members of the execution
character set shall be represented by corresponding members of the source
character set or by /escape sequences/ consisting of the backslash
followed by one or more characters. A byte with all bits set to 0, called
the /null character/, shall exist in the basic execution character set; it
is used to terminate a character string.

[3] Both the basic source and basic execution character sets shall have the
following members: the 26 /uppercase letters/ of the Latin alphabet

Reste inchangé, juste une petite différence [c'est moi qui souligne]:
In the *basic* execution character set, there shall be control characters
representing alert, backspace, carriage return, and new line.

[4] A /letter/ is an uppercase letter or a lowercase letter as defined
above; in this International Standard the term does not include other
characters that are letters in other alphabets.

[5] The universal character name construct provides a way to name other
characters.

Forward references: universal character names (6.4.3), character constants
(6.4.4.4), preprocessing directives (6.10), string literals (6.4.5),
comments (6.4.9), string (7.1.1).



Antoine



Avatar
Vincent Lefevre
Dans l'article <c5lg7q$5vd$,
Antoine Leca écrit:

On ne doit pas avoir la même manière de lire...

Je cite:

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

« N'importe quel compilateur », c'est clairement à mon sens
l'obligation de ne pas dépendre du compilateur. Donc de ne pas
s'intéresser aux particularités de tel ou tel.


Non, justement s'il veut pouvoir compiler avec n'importe quel
compilateur, il faut s'intéresser aux particularités de tous
les compilateurs (sous réserve que celles-ci "respectent la
norme"), tout comme il ne faut pas supposer que int, long et
long long aient telle ou telle taille (cf discussion récente
sur le fait que Microsoft utilisait des tailles particulières).

Parce que quand on compile, les constantes du source comme 'a' ou
'é' sont stockées en dur dans le code généré.


Oui. Ces valeurs sont d'ailleurs celles dans le jeu de caractères
d'exécution.


qui n'est pas forcément défini à l'avance, dans la pratique.


Je ne sais pas de quelle pratique tu parles.


Dans la pratique, sous Unix, les locales ne sont pas fixes et changent
souvent (d'un utilisateur à l'autre, ou même des programmes qui les
changent, par exemple des scripts pour que la commande "sort" ait un
comportement différent sur le tri, ou les programmes utilisant GTK+,
qui passent en UTF-8). Suivant les locales et en particulier le jeu de
caractères choisi à l'exécution, on obtient des caractères différents.

Dans la norme, c'est tellement défini à l'avance que cela l'est
avant même le début de la compilation: ce codage est « défini par
l'implémentation », ce qui signifie que le fournisseur du
compilateur est obligé de le préciser dans la documentation.


En tout cas, ce n'est pas le cas avec gcc.

Si on exécute ce code dans un environnement ayant un jeu de
caractères différent (c'est facile à changer sous Unix),


Non.
D'abord, un 'a' est toujours un 'a'.


Ça ne veut rien dire.


Cela veut dire que avec *nix, tu peux changer autant que tu veux
l'encodage de 'é'. Mais pas celui de 'a'.


OK pour cette précision. Le problème concerne les caractères qui
peuvent varier (comme é, et éventuellement a sur des systèmes non
POSIX).

Ensuite, si tu changes de locale (ce qui toujours un acte
volontaire, il faut appeler setlocale()) sans tenir compte des
encodages, tu invoques un comportement dépendant de la locale. Si
ton programme agit différement dans ces cas-là, il n'est plus
strictement conforme, et encore une fois on est sorti du propos de
cette enfilade.


Mais c'est bien ce que je disais ici:
<20040410000611$.


Pas tout-à-fait.

Ce que disait, c'était
: > Pour les entrées/sorties on peut fonctionner avec des fichiers textes.
:
: Même avec les fichiers texte. La norme dit:
[couic citation clause 4, paragraphe 5]
: 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).

[Merci alphanet]

Or ici, je fais clairement la distinction entre les caractères du jeu de
base (comme 'a'), qui ne change pas à l'exécution et donc peuvent entrer
dans des programmes strictement conformes, et les caractères comme 'é' qui
ne le peuvent pas. Autrement dit, l'archétype HelloWorld.c est strictement
conforme.


D'accord qu'il y ait une différence si tu ne considères que le jeu de
base. Mais cela n'empêche que c'est *dépendant de l'implémentation*.
Tu obtiendras toujours un 'a', mais son code est dépend de
l'implémentation.

on obtiendra un résultat différent (concernant les caractères, pas
les codes eux-mêmes). Les constantes caractère du source sont bien
liées à l'environnement de compilation et non pas à
l'environnement d'exécution.


Mais cela n'a rien à voir. On peut parfaitement avoir un compilateur
*nix qui accepte en paramètre la locale d'encodage des caractères.
Ce sera la manière utilisée pour encoder le binaire, autrement dit
le jeu d'exécution.


Mais ce n'est pas ce qui se passe avec gcc par exemple.


Non. Et alors ?


Ceci explique qu'avec gcc (mais pas seulement), les constantes
caractère sont liées à l'environnement de compilation.

En fait, le jeu de caractères de base, c'est ASCII sauf $ @ ` (c'est
un point qui a été éclairci en C99).


Ça a changé par rapport au draft WG14/N869 alors (je ne le savais
pas); N869 dit seulement "at least".


Après vérification, oui.
Bizarre, je me souvenais bien de cette modification, on en avait parlé à
Copenhague (juin 98), mais j'aurais cru que cela avait été écrit plus tôt
que N877 (mars 99) dans le texte de la norme (N869 est daté janvier 99). On
a beaucoup acceléré le développement à ce moment-là, pour ne pas devenir C00
!

Le nouveau (et définitif) texte est:
5.2 Environmental considerations

5.2.1 Character sets

[1] Two sets of characters and their associated collating sequences shall be
defined: the set in which source files are written (the /source character
set/), and the set interpreted in the execution environment (the /execution
character set/). Each set is further divided into a /basic character set/,
whose contents are given by this subclause, and a set of zero or more
locale-specific members (which are not members of the basic character set)
called /extended characters/. The combined set is also called the /extended
character set/. The values of the members of the execution character set are
implementation-defined.

[2] In a character constant or string literal, members of the execution
character set shall be represented by corresponding members of the source
character set or by /escape sequences/ consisting of the backslash
followed by one or more characters. A byte with all bits set to 0, called
the /null character/, shall exist in the basic execution character set; it
is used to terminate a character string.

[3] Both the basic source and basic execution character sets shall have the
following members: [...]


Faut-il comprendre le "shall have" comme un "shall have only" ou un
"shall have at least". Dans la langue courante, ce serait un "shall
have at least", mais qu'en est-il de l'interprétation de la norme?

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




3 4 5 6 7