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

Portabilité chaine

16 réponses
Avatar
Stephane Legras-Decussy
bonjour,

j'ai une question qui me laisse perplexe au sujet
de l'encodage des caractères.

j'ai fait une fonction qui est capable
d'afficher correctement (en openGL) une chaine
du code ascii complet jusqu'à 255.

pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);

si je l'appelle avec une chaine "en dur", comme ça :

mafonct("ça me prend la tête");

pas de warning et
ça fonctionne bien chez moi (XP codeblocks gcc -W -Wall),
mais qu'en est-il de la portabilité ?
quel problème peuvent se poser en compilant ça ailleur ?
c'est quoi le type d'une chaine constante passée comme
ça ?

Merci !

10 réponses

1 2
Avatar
Eric Levenez
Le 27/08/07 23:59, dans <46d3494e$0$30659$, « Stephane
Legras-Decussy » a écrit :

j'ai fait une fonction qui est capable
d'afficher correctement (en openGL) une chaine
du code ascii complet jusqu'à 255.


L'ASCII est un code 7 bits et s'arrête à 127.

pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);

si je l'appelle avec une chaine "en dur", comme ça :

mafonct("ça me prend la tête");

pas de warning et
ça fonctionne bien chez moi (XP codeblocks gcc -W -Wall),


Gcc devrait afficher : warning: pointer targets in passing argument 1 of
'mafonct' differ in signedness

mais qu'en est-il de la portabilité ?


Pas terrible, surtout que tu crois que "ç" et "ê" c'est de l'ASCII.

quel problème peuvent se poser en compilant ça ailleur ?


Le jeux de caractères du compilateur n'est peut-être pas ASCII du tout, sans
parler que les caractères spéciaux sont peut-être encodé en UTF-8 par ton
éditeur et pas juste dans un code 8 bits comme tu le penses.

c'est quoi le type d'une chaine constante passée comme
ça ?


C'est tout faux dans le principe et dans la réalisation :-)

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

Avatar
Stephane Legras-Decussy
"Eric Levenez" a écrit dans le message de news:
C2F919A1.B1592%

L'ASCII est un code 7 bits et s'arrête à 127.


ok, abus de langage...
ma table c'est ISO 8859-1


Gcc devrait afficher : warning: pointer targets in passing argument 1 of
'mafonct' differ in signedness


oui, j'ai pas aimé qu'il me dise rien sur le coup...

Le jeux de caractères du compilateur n'est peut-être pas ASCII du tout,
sans
parler que les caractères spéciaux sont peut-être encodé en UTF-8 par ton
éditeur et pas juste dans un code 8 bits comme tu le penses.

c'est quoi le type d'une chaine constante passée comme
ça ?


C'est tout faux dans le principe et dans la réalisation :-)


alors ça marche juste parce que mon editeur est aussi
en ISO 8859-1, c'est ça ?

j'oublie l'idée alors...


Avatar
Eric Levenez
Le 28/08/07 0:58, dans <46d3573a$0$440$, « Stephane
Legras-Decussy » a écrit :

alors ça marche juste parce que mon editeur est aussi
en ISO 8859-1, c'est ça ?


C'est une des conditions.

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

Avatar
Pascal Bourguignon
"Stephane Legras-Decussy" writes:

"Eric Levenez" a écrit dans le message de news:
C2F919A1.B1592%

L'ASCII est un code 7 bits et s'arrête à 127.


ok, abus de langage...
ma table c'est ISO 8859-1


Gcc devrait afficher : warning: pointer targets in passing argument 1 of
'mafonct' differ in signedness


oui, j'ai pas aimé qu'il me dise rien sur le coup...

Le jeux de caractères du compilateur n'est peut-être pas ASCII du tout,
sans
parler que les caractères spéciaux sont peut-être encodé en UTF-8 par ton
éditeur et pas juste dans un code 8 bits comme tu le penses.

c'est quoi le type d'une chaine constante passée comme
ça ?


C'est tout faux dans le principe et dans la réalisation :-)


alors ça marche juste parce que mon editeur est aussi
en ISO 8859-1, c'est ça ?

j'oublie l'idée alors...


Pas forcement, mais il faut savoir ce qu'on fait. Si tu veux gerer
les caracteres non ASCII, le plus sur c'est de le faire explicitement
(utilier wchar_t et les fonctions associees).

Il faut savoir quel encodage est utilise dans le source (configurer
l'editeur), par le compilateur (configurer le locale avec LC_CTYPE
etc), et par les bibliotheques et autres routines externes comme le
systeme ou opengl. (Le systeme ne gere pas forcement lui meme
d'encodage, mais les file systems peuvent le faire). En sachant cela
on peut utiliser la bonne fonction d'encodage avant d'envoyer les
octets a ces bibliotheques pour etre sur que ca fonctionne bien.

--
__Pascal Bourguignon__ http://www.informatimago.com/

COMPONENT EQUIVALENCY NOTICE: The subatomic particles (electrons,
protons, etc.) comprising this product are exactly the same in every
measurable respect as those used in the products of other
manufacturers, and no claim to the contrary may legitimately be
expressed or implied.



Avatar
Antoine Leca
En news:46d3494e$0$30659$,
Stephane Legras-Decussy va escriure:
j'ai une question qui me laisse perplexe au sujet
de l'encodage des caractères.


Je ne suis pas sûr que ma réponse va te sortir de ta perplexité.

j'ai fait une fonction qui est capable
d'afficher correctement (en openGL) une chaine
du code ascii complet jusqu'à 255.


Mmm. Es-tu certain ? Le code ASCII s'étendant de 0 à 127, l'affichage du
caractère de code 0 en C est un peu sportif et demande d'utiliser un type
spécial pour représenter les chaînes, à savoir un tableau de char _et_ une
indication de la longueur; par contre, la manière de déclarer le type de
base, signé ou non signé ou rien n'est pas importante.


pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);


Hmmm. Bin voilà, je crois bien que cela ne fonctionne pas, justement. En
tous cas, cela ne réussira pas à afficher correctement

unsigned char test[8] = "123 abc!"
unsigned char test2[8] = "123abc!"

(ou alors la fonction est douée de pouvoirs magiques, du genre elle sait que
la chaîne fait toujours 8 caractères...)


si je l'appelle avec une chaine "en dur", comme ça :

mafonct("ça me prend la tête");

pas de warning et
ça fonctionne bien chez moi (XP codeblocks gcc -W -Wall),
mais qu'en est-il de la portabilité ?


Tu as un potentiel souci de portabilité sur l'encodage des caractères. Pour
que ton programme fonctionne comme prévu, il est nécessaire que les
sous-chaînes "ç" et "ê" soient interprétés de la manière par l'environnement
de développement (en gros, ce que tu vois à l'écran, plus éventuellement les
traductions que peut faire le compilateur en entrée) et par l'environnement
d'exécution.

Donc, s'il s'agit de la même machine et du même compte utilisateur pour
écrire, compiler et exécuter, qu'il n'y a pas de paramétrage zar-bi du
compilateur, et que les paramètres d'affichage ne varient pas entre les deux
moments, cela va marcher.
Bien entendu, là dedans, ce qui importe ce n'est pas l'identité de la
machine ou du compte utilisateur, mais bien plutôt l'ensemble des paramètres
lié à l'encodage des caractères que cela induit.

Quelques exemples de dysfonctionnements :
- machine IBM (EBCDIC), environnement d'écriture en français (ç=xE0),
environnement d'exécution en allemand (xE0=Ö), "Öa me prend la tête"
- ta propre machine Windows, éditeur de texte «à fond blanc» (notepad ou
autre), exécution dans une boîte DOS, "þa me prend la tÛte"
- même machine Windows, l'utilisateur qui lis le texte est un chinois, oh
les beaux idéogrames ! mais d'où viennent-ils donc ?
- la machine où le texte est composé est la tienne (sous Windows), le
programme est compilé sous *nix, "?me prend la t?"
- tout pareil, mais l'utilisateur qui lis est un hacker, il rajoute export
LC_CTYPE=iso-8859-1, et maintenant il voit "ça me prend la tête"...
- alors il lis le fichier dans son éditeur, sauvegarde en UTF-8, OK c'est
bon, CVS commit, tu récupères par CVS update, tu recompiles, et toi tu lis
"ça me prend la tête"...
- compilateur GCC, on peut passer des options -finput-charset et -fexec-charset= différentes... si elles sont un peu cachées, cela peut
faire des trucs bien drôles, aussi.


Bref, une bonne manière avec C99 c'est d'écrire

mafonct("u00E7a me prend la tu00EAte");

mais je reconnais que ce n'est pas joli joli. De plus, la quasi totalité des
éditeurs de textes ne sont pas capables de remplacer cela à la volée par ç
et ê ; et il existe une bonne quantité de compilateurs qui ne savent pas
interpréter comme il faut les UCN (à commencer par GCC/Mingw si on ne sait
pas l'utiliser correctement, car il va générer de l'UTF-8 par défaut !)
Autrement dit, ce n'est pas la panacée en terme de portabilité.

Une autre solution, c'est d'exporter les chaînes de texte ailleurs (genre
dans un fichier, ou dans des ressources).


quel problème peuvent se poser en compilant ça ailleur ?


Que le compilateur attende un encodage différent de celui réellement
utilisé, que cet encodage présente des séquences interdites (cas typique :
UTF-8), et que le compilateur refuse de générer du code avec ces séquences
interdites (toujours avec UTF-8, cela arrive pour éviter que du code avec
des séquences genre "xC0xAF..xC0xAF" soit compilé, le but étant de
protéger de certains bogues dans des logiciels trop largement répandus...)
Et là, cela ne passe plus du tout :-(


c'est quoi le type d'une chaine constante passée comme
ça ?


char[N] avec N>20 (22 en UTF-8, par exemple).


Antoine

Avatar
Stephane Legras-Decussy
"Antoine Leca" a écrit dans le message de news:
fb3sl2$p2q$
En news:46d3494e$0$30659$,
[snip]


un grand merci pour cette réponse très documentée
que je vais essayer de comprendre doucement... :-)

Avatar
Vincent Lefevre
Dans l'article <fb3sl2$p2q$,
Antoine Leca écrit:

En news:46d3494e$0$30659$,
Stephane Legras-Decussy va escriure:
pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);


Hmmm. Bin voilà, je crois bien que cela ne fonctionne pas, justement. En
tous cas, cela ne réussira pas à afficher correctement

unsigned char test[8] = "123 abc!"
unsigned char test2[8] = "123abc!"

(ou alors la fonction est douée de pouvoirs magiques, du genre elle
sait que la chaîne fait toujours 8 caractères...)


Dans test2, la chaîne ne fait que 3 caractères, donc aucun problème.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Antoine Leca
En news:20070830075311$,
Vincent Lefevre <vincent+ va escriure:
Dans l'article <fb3sl2$p2q$,
Antoine Leca écrit:

En news:46d3494e$0$30659$,
Stephane Legras-Decussy va escriure:
pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);


Hmmm. Bin voilà, je crois bien que cela ne fonctionne pas,
justement. En tous cas, cela ne réussira pas à afficher correctement

unsigned char test[8] = "123 abc!"
unsigned char test2[8] = "123abc!"

(ou alors la fonction est douée de pouvoirs magiques, du genre elle
sait que la chaîne fait toujours 8 caractères...)


Dans test2, la chaîne ne fait que 3 caractères, donc aucun problème.


Tu as trop élagué. Je reprends donc le texte qui a disparu (avec ma prose,
pour bien comprendre où se situe le problème) :

::> j'ai fait une fonction qui est capable
::> d'afficher correctement (en openGL) une chaine
::> du code ascii complet jusqu'à 255.
::
:: Mmm. Es-tu certain ? Le code ASCII s'étendant de 0 à 127, l'affichage
:: du caractère de code 0 en C est un peu sportif et demande d'utiliser
:: un type spécial pour représenter les chaînes, à savoir un tableau de
:: char _et_ une indication de la longueur; par contre, la manière de
:: déclarer le type de base, signé ou non signé ou rien n'est pas
:: importante.

Et je maintiens : dans ce contexte-là, le tableau teste2 contient une chaîne
de 8 caractères « ascii complet ».


Et l'« ascii complet », en C, c'est galère. En tous cas, ce n'est pas
trivial et évident.


Antoine



Avatar
PulkoMandy
Le Thu, 30 Aug 2007 14:50:56 +0200, Antoine Leca
a écrit:

En news:20070830075311$,
Vincent Lefevre <vincent+ va escriure:
Dans l'article <fb3sl2$p2q$,
Antoine Leca écrit:

En news:46d3494e$0$30659$,
Stephane Legras-Decussy va escriure:
pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);


Hmmm. Bin voilà, je crois bien que cela ne fonctionne pas,
justement. En tous cas, cela ne réussira pas à afficher correctement

unsigned char test[8] = "123 abc!"
unsigned char test2[8] = "123abc!"

(ou alors la fonction est douée de pouvoirs magiques, du genre elle
sait que la chaîne fait toujours 8 caractères...)


Dans test2, la chaîne ne fait que 3 caractères, donc aucun problème.


Tu as trop élagué. Je reprends donc le texte qui a disparu (avec ma
prose,
pour bien comprendre où se situe le problème) :

::> j'ai fait une fonction qui est capable
::> d'afficher correctement (en openGL) une chaine
::> du code ascii complet jusqu'à 255.
::
:: Mmm. Es-tu certain ? Le code ASCII s'étendant de 0 à 127, l'affichage
:: du caractère de code 0 en C est un peu sportif et demande d'utiliser
:: un type spécial pour représenter les chaînes, à savoir un tableau de
:: char _et_ une indication de la longueur; par contre, la manière de
:: déclarer le type de base, signé ou non signé ou rien n'est pas
:: importante.

Et je maintiens : dans ce contexte-là, le tableau teste2 contient une
chaîne
de 8 caractères « ascii complet ».


Et l'« ascii complet », en C, c'est galère. En tous cas, ce n'est pas
trivial et évident.


Antoine



Il faut faire des chaines "pascal" (la longueur est indiquée sous forme
d'entier quelque part, la chaine n'est pas forcément terminée par un 0.
Avantage: on peut faire de l'ascii complet, la fonction strlen() est
beaucoup plus simple à implémenter, strcat peut être plus rapide (pas
besoin de chercher la fin d'une chaine pour savoir ou mettre la deuxième).
Inconvénient: La longueur de la chaine est limitée à la valeur maximum de
l'entier que l'on utilise. En pascal, c'est un entier sur 8 bits, donc les
chaines font 255 caractères maximum, et 0 au minimum.




Avatar
Vincent Lefevre
Dans l'article <fb6efh$gjg$,
Antoine Leca écrit:

En news:20070830075311$,
Vincent Lefevre <vincent+ va escriure:
Dans l'article <fb3sl2$p2q$,
Antoine Leca écrit:

En news:46d3494e$0$30659$,
Stephane Legras-Decussy va escriure:
pour que ça fonctionne elle est déclarée comme ça :

void mafonct(unsigned char * s);


Hmmm. Bin voilà, je crois bien que cela ne fonctionne pas,
justement. En tous cas, cela ne réussira pas à afficher correctement

unsigned char test[8] = "123 abc!"
unsigned char test2[8] = "123abc!"

(ou alors la fonction est douée de pouvoirs magiques, du genre elle
sait que la chaîne fait toujours 8 caractères...)


Dans test2, la chaîne ne fait que 3 caractères, donc aucun problème.


Tu as trop élagué. Je reprends donc le texte qui a disparu (avec ma prose,
pour bien comprendre où se situe le problème) :

::> j'ai fait une fonction qui est capable
::> d'afficher correctement (en openGL) une chaine
::> du code ascii complet jusqu'à 255.
::
:: Mmm. Es-tu certain ? Le code ASCII s'étendant de 0 à 127, l'affichage
:: du caractère de code 0 en C est un peu sportif et demande d'utiliser
:: un type spécial pour représenter les chaînes, à savoir un tableau de
:: char _et_ une indication de la longueur; par contre, la manière de
:: déclarer le type de base, signé ou non signé ou rien n'est pas
:: importante.

Et je maintiens : dans ce contexte-là, le tableau teste2 contient une chaîne
de 8 caractères « ascii complet ».


Je maintiens: la chaîne n'a que 3 caractères. Si tu veux parler des
8 caractères, il faut parler de tableau, pas de chaîne, qui par
définition se termine par le caractère nul. Si on commence à modifier
les définitions standard, on ne s'y retrouve plus...

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)




1 2