Utiliser des charactères étendus

Le standard ISO/ANSI C contient, dans une correction qui fut ajoutée en 1995, un type de caractère codé sur 16 bits wchar_t, un ensemble de fonctions comme celles contenues dans <string.h> et <ctype.h> (déclarées respectivement dans <wchar.h> et <wctype.h>), et un ensemble de fonctions de conversion entre char * et wchar_t * (déclarées dans <stdlib.h>).

Tout ce qu’un programme doit faire c’est appeler setlocale(LC_ALL,""); pour que ces fonctions fassent ce qu’il faut selon la locale de l’utilisateur.

Pourquoi les utiliser?

Avant, les ordinateurs traitaient des données encodées avec un jeux de caractères limité char qui peut prendre 256 valeurs différentes, ce qui correspond aux entrées dans les tables latines de l”ISO. D’autre part, le caractère large peut prendre plus de 65536 valeurs, ce qui correspond aux valeurs Unicode. Il s’agit d’une norme internationale plus récente qui permet l’encodage de caractères pour pratiquement toutes les langues et les symboles couramment utilisés.

wchar_t est un type de caractère étendu. Il est utilisé pour représenter des caractères qui nécessitent plus de mémoire qu’un caractère normal.

Il est conseillé de l’utiliser si vous souhaitez que votre programme gère correctement les caractères spéciaux tels que les caractères accentués.

Exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
	Démonstration des "wide characters"

	Pour compiler ce programme:
	$ gcc wide.c -o wide -Wall
*/
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

size_t get_sizeof(char * s);

int main(void)
{				
	char    *s1 =  "Démonstration";
	wchar_t *s2 = L"Démonstration";
	
	setlocale(LC_ALL, "");

	wprintf(L"      longueur de la chaine char* s1: %2ld.\n", strlen(s1));
	wprintf(L"    longeur de la chaîne wchar_t *s2: %2ld.\n", wcslen(s2));

	wprintf(L"   taille des caractères de char *s1: %2ld.\n", sizeof(*s1));
	wprintf(L"taille des caractères de wchar_t *s2: %2ld.\n", sizeof(*s2));

	wprintf(L"        mesure de la chaine char *s1: %2ld.\n", get_sizeof(s1));

	return 0;
}

size_t get_sizeof(char *s)
{
	char *ps;
	ps = s;
	size_t result=0, current_size=0;

	while(*ps != '\0')
	{
		current_size = sizeof(*ps);
		result += current_size;
		ps++;
	}

	return result;
}

Le programme ci-dessous affiche le résultat suivant:

      longueur de la chaine char* s1: 14.
    longeur de la chaîne wchar_t *s2: 13.
   taille des caractères de char *s1:  1.
taille des caractères de wchar_t *s2:  4.
        mesure de la chaine char *s1: 14.

La sortie ci-dessus montre bien qu’il y a quelquechose d’étrange: le mot Démonstration fait 13 caractères de longs, alors que la fonction strlen() renvoie une longueur de 14 caractères. C’est d’autant plus étrange que la fonction équivalente wcslen() pour les caractères étendus renvoie bien le nombre correct de caractères: 13.

Et bien ceci s’explique par le fait que le type char représente les caractères sur 1 octet et que pour représenter le caractère é il utilise deux valeurs de 1 octet. Alors que le type wchar_t utilise 2 à 4 octets par caractère selon l’implémentation.

Ici, dans notre exemple, le mot Démonstration a une taille de 14 octets lorsqu’il est représenté en char et 52 octets lorsqu’il est représenté en wchar_t.

Avertissement

Il est évident que si vous écrivez un programme devant mesurer la taille des mots il ne retournera pas un résultat correct dans toutes les langues si vous utilisez le type char.

Utiliser le type wchar_t

Faire appel à setlocale()

Et bien pour commencer, comme dit précédemment, tout ce qu’un programme doit faire c’est appeler setlocale(LC_ALL,"");.

Il est donc nécessaire d’include <locale.h> dans votre programme, et de procéder à son appel avant tout affichage.

Représenter une chaîne étendue

Comme on peut le voir dans l’exemple ci-dessus, à la ligne 17:

wchar_t *s2 = L"Démonstration"; est la déclaration d’une chaîne de caractères étendue. En fait, il suffit tout simplement de préfixer une déclaraction de chaîne normale avec L.

Et c’est pareil pour les caractères, par exemple on aurait pu déclarer:

wchar_t c = L'ù';

Et, attention, le type char ne gère pas ce cas.

Par exemple le programme ci-dessous compile sans erreur:

#include <wchar.h>
#include <locale.h>

int main(void)
{
	wchar_t c=L'é';

	setlocale(LC_ALL, "");

	wprintf(L"le caractère est: %lc.\n", c);

	return 0;
}

Alors que le programme ci-dessous ne va pas faire ce à quoi on pourrait s’attendre:

#include <stdio.h>

int main(void)
{
	char c='é';

	printf("le caractère est: %c.\n", c);

	return 0;
}

Lors de la compilation gcc émet deux alertes:

warning: multi-character character constant [-Wmultichar]
char c='é';
       ^~~~
warning: overflow in implicit constant conversion [-Woverflow]

Et si on exécute ce dernier il n’affichera pas le caractère é mais:

le caractère est: �.

Conclusion

Je vous invite à porter de l’intérêt à cela, et pas uniquement lorsque vous programmez en C, mais dès lors que vous utilisez une application manipulant des chaînes de caractères et proposant l’usage de ces types.

Cet article est loin d’être complet et exhaustif, pour allez plus loin, la librairie C offre toutes les fonctions nécessaires pour utiliser le type wchar_t, ainsi que des fonctions de convertions entre char et wchar_t.