[Résolu] CHAR un mystère

Bonjour à tous,
J'ai un problème de compréhension avec les déclarations CHAR.
On peut dire que les déclarations suivantes sont équivalentes.

char message0 [] = {'O', 'h', '!', '\0'};
char message1[] = "Oh!";

En balayant les différentes positions du tableau.

	uint8_t k = 0;
	int numChar = 0;
	while(message[k] != '\0'){
		numChar = message[k] * 1;
		Serial.println(numChar);
		k++;
	}

On a les codes ASCII des caractères, à savoir :

[color=blue]79, 104 et 33[/color]

L'environnement Arduino n'étant pas "copain" avec les caractères accentués de notre belle langue.
Si l'on répète l'opération avec :

char message0 [] = {'é', 'è', '!', '\0'};
char message1[] = "éè!";

On obtient pour :

        char message0 [] = {'é', 'è', '!', '\0'};
	uint8_t k = 0;
	int numChar = 0;
	while(message[k] != '\0'){
		numChar = message[k] * 1;
		Serial.println(numChar);
		k++;
	}

On obtient :

[color=blue]-87, -88 et 33[/color]

Ce n'est pas directement exploitable mais on peut faire un traitement avec switch ou en ajoutant, par exemple 256 (dans ce cas il faut modifier le jeu de caractères).
Par contre lorsqu'on fait:

        char message0 [] = "'éè";
	uint8_t k = 0;
	int numChar = 0;
	while(message[k] != '\0'){
		numChar = message[k] * 1;
		Serial.println(numChar);
		k++;
	}

On obtient :

[color=blue]-61, -87, -61, -88 et 33[/color]

Ce résultat est, bien sur, également exploitable. On dirait un genre de caractère d’échappement.
Je souhaiterai juste savoir d'où vient cette différence de résultat.
Merci pour vos précisions.
@+

Hello,

char est par défaut signé avec avr-gcc, essaie avec "unsigned char", et tu auras l'équivalent avec des valeurs positives

Ensuite : vérifie l'encodage de tes sources : sont-elles en Latin-1, UTF-8 ou Unicode ?
Dans le premier cas, 'é' prendra un caractères, deux en UTF-8, et tous les caractères seront encodés en 16 bits en Unicode.

EDIT: vu ce que tu affiches, c'est bien de la retranscription UTF-8.

Solution : passer ton code-source en Latin-1 + utiliser des unsigned char et recompiler.

Salut,
Merci pour ta réponse.

XavierMiller:
char est par défaut signé avec avr-gcc, essaie avec "unsigned char", et tu auras l'équivalent avec des valeurs positives

Avec unsigned char, j’obtiens :

unsigned char message0 [] = {'é', 'è', '!', '\0'};
unsigned char message1[] = "éè!";
[color=blue]169, 168, 33[/color] et
[color=blue]-87, -88, 33[/color]

XavierMiller:
Ensuite : vérifie l'encodage de tes sources : sont-elles en Latin-1, UTF-8 ou Unicode ?
Dans le premier cas, 'é' prendra un caractères, deux en UTF-8, et tous les caractères seront encodés en 16 bits en Unicode.
EDIT: vu ce que tu affiches, c'est bien de la retranscription UTF-8.
Solution : passer ton code-source en Latin-1 + utiliser des unsigned char et recompiler.

J'utilise Notepad++ avec un encodage UTF-8(sans BOM).
Qu'elle est la procédure pour passer en Latin-1 car je ne vois pas dans les paramètres de Notepad++ de Latin-1
ou bien comment faire directement dans l'environnement Arduino.
@+

Tu as un menu "Encoding"

Re,

XavierMiller:
Tu as un menu "Encoding"

Ok, autant pour moi, il fait lire ISO_8859-1.
Mais tout cela ne change pas grand chose sur les résultat.
@+

normalement oui : en iso-8859-1 ou Latin-1, les caractères français sont dans la plage 128 à 255 ou -256 à -1
le compilateur ne fait normalement RIEN aux chaînes en dur dans le code, il les prend telles quelles, entre le premier " et le dernier ", quel que soit l'encodage de caractères.

J'ai fait quelques essais et la compilation dans l'IDE ne passe pas si on n'utilise pas l'encodage UTF-8.
De ce que j'ai vu le "preprocesseur" de la couche arduino ne gère pas d'autre forme d'encodage et il sort une erreur.

Je n'ai pas essayé en appelant directement avr-gcc en ligne de commande.

Re,
Je reviens sur mon interrogation initial, pourquoi :
{é', '\0'} -> renvoi 1 octet
"é" -> renvoi 2 octets

Bon, on va essayer d'éclairer la chose :

Préambule : un littéral désigne une suite de caractères stockés dans un code source (tels qu'ils apparaissent à l'écran de ton éditeur préféré), et censés représenter une valeur.
Un des boulots du compilo est d'arriver à comprendre la valeur réelle que représente un littéral.

Pour le compilateur, le littéral 'é' représente simplement un nombre codé sur un octet, en l'occurence le nombre 169 (pourquoi 169 => on va voir plus loin).

Si tu le transfères dans un int (=entier signé), et que tu affiches la valeur du int, tu obtiens 169-256= -87
D'un point de vue informatique, le contenu de la variable est le même. C'est juste que tu lui demandes de l'afficher en tant que nombre signé, d'où le -87. Si ton numChar était de type byte ou uint8_t, cela afficherait 169.

Ce qui est important, c'est que la valeur binaire représentée par le littéral présent dans ton code source (peu importe que tu aies codé 'é' ou 169), est utilisée comme telle par le compilo lorsqu'il génère l'exécutable : elle fait directement partie des instructions machine.

"éè" est une chaîne de caractères.
Le compilateur la stocke en RAM à partir d'une certaine adresse : une suite d'octets avec un zéro terminal ajouté.
Et le code exécutable généré comporte, à l'endroit de ton instruction, un renvoi vers cette adresse mémoire.
(je ne parle pas ici de l'utilisation de PROGMEM : c'est un autre sujet).

Et il se trouve que le compilateur traduit ton texte en utilisant la norme UTF-8 pour stocker les valeurs équivalentes en RAM.
UTF-8 est différent de ASCII.
En fait, à partir du 128ème caractère, c'est le bordel et il existe plusieurs "normes universelles" : ASCII étendu, UTF-8, ANSI, ISO, ...

En UTF-8, les caractères spéciaux occupent deux octets : un marqueur C3 (en hexa, soit 195, soit encore 195-256 = -61 si affiché en tant qu'entier signé) suivi de la valeur associée au caractère accentué pour cette nomenclature : 169 pour é (=> -87) et 168 pour è (=> -88).

donc "aéè" devient en RAM : 97.195.169.195.168.0

Si tu envoies cette chaîne de caractère vers le terminal série de l'IDE Arduino, elle s'affichera mal car celui-ci ne fonctionne pas en UTF-8.
Afficher les caractères accentués sur le terminal série est possible, mais une étape de transco préalable est nécessaire.
Ou alors il faut utiliser un littéral différent (séquences d'échappement au lieu de é, è, etc => pas joyeux)

Cerise sur le gâteau : imagine que tu déclares tous tes libellés dans un seul fichier source, qui ne contient que ça.
Et que derrière, tu utilises le même fichier source par include pour compiler différents programmes pour différentes plateformes.
Par exemple un programme pour ton arduino, et un programme pour ton PC (windows ou linux).
Et ben selon les plateformes et/ou les compilos, tu ne retrouveras pas exactement les mêmes octets en mémoire, représentant ta chaîne de caractères. Cela dépend de la norme de représentation des caractères, utilisée par le compilo pour ta plateforme cible.
Pour peu que tes programmes dialoguent entre eux, tu te retrouves vite devant un problème de vocabulaire commun.

C'est clair ou je recommence ?

Salut bricoleau;

bricoleau:
C'est clair ou je recommence ?

Merci pour toutes ces informations et il n'est pas nécessaire de reprendre l'explication.
J'ai retrouvé des explications complémentaires en regardant de plus près le standard UTF-8.

ici_le_lien