Comprendre le type char et ses variantes
Le langage C++
hérite du langage
C une contrainte auto imposée :
ne faire payer aux programmeuses et aux programmeurs que le prix (en temps et
en espace) qu'elles et ils ont explicitement accepté de payer. Cela a
une incidence sur la conception de ce qu'est une bonne représentation
interne pour les types voués (entre autres) à la représentation
des caractères.
En ce sens, C++
diffère philosophiquement de Java et des langages
.NET. En effet,
Java et les langages
.NET ont
choisi de fixer le sens et la représentaiton interne des types caractères :
les types char (plateforme
Java; classe immutable
correspondante : Character) et
System.Char (plateforme
.NET, dont un trouve
un alias nommé char en
C#) ont un sens ent
une représentation interne fixés par la norme de leurs plateformes
respectives (entier non signé sur 16 bits
destiné à rperésenter un caractère Unicode).
Le langage C++
offre aussi un type spécialement pensé pour représenter
des caractères Unicode, mais il s'agit du type wchar_t,
le « w » signifiant Wide
(prendre au sens de caractère étendu) plutôt que du type
char. Historiquement, en langage
C, le type char
a joué un double rôle :
- Représenter un caractère, habituellement
ANSI ou ASCII (donc encodable sur huit
bits), et
- Représenter un octet (plus précisément : un byte).
Les concepteurs de
C étaient
minimalistes dans leur approche et n'ont pas implémenté un type spécifiquement
pour représenter du texte, y allant plutôt dans l'optique inverse et suggérant
par un nom de représenter un caractère sur un petit entier. à cette époque,
les préoccupations d'internationalisation qui sont aujourd'hui à l'avant-plan
(beaucoup grâce à Internet) n'étaient pas aussi importantes (en fait,
n'étaient probablement pas importantes du tout) pour la majorité des
programmeuses et des programmeurs
Puisque le type char joue en C et en C++
le rôle traditionnel de type
entier de taille 1, donc de représentation
pour la plus petite unité adressable directement à l'aide d'un
type du langage, il est crucial que les accès aux données de ce
type soient des plus efficaces.
C'est pourquoi le type char est différent
de tous les autres types entiers :
- Là où, sur toutes les plateformes, int
équivaut à signed int,
short équivaut à signed short
et long équivaut à
signed long, le type char n'équivaut
pas nécessairement au type signed char.
En fait, selon les plateformes, le type char sera soit signé, soit non signé. Les implémenteurs du compilateur sur une
plateforme donnée ont la latitude d'utiliser la version (signée ou non) qui
sera la plus efficace pour la plateforme en fonction de laquelle le code sera
généré
- La taille d'un char est fixée par la
norme du langage. Par définition, sizeof(char)==1.
Ceci diffère de la taille des autres types entiers pour lesquels la
norme ne fixe pas de taille, seulement une relation d'ordre dans les tailles :
- sizeof(char) <= sizeof(short)
- sizeof(short) <= sizeof(int)
- sizeof(int) <= sizeof(long)
- Par définition aussi, sizeof(char)==sizeof(signed char)
et sizeof(char)==sizeof(unsigned char),
ce qui est raisonnable
- Les règles pour affecter un signed char
à un unsigned char ou l'inverse
sont les mêmes que les règles s'appliquant à l'affectation
d'un int à un unsigned int
et inversement, incluant les risques de débordement
- Il en va de même pour ce qui est d'affecter un char à un
signed char ou à un unsigned char,
selon le signe du type char sur une plateforme
donnée
- Les types char, signed char
et unsigned char sont trois types
distincts l'un de l'autre, peu importe que char soit signé ou non.
à titre d'exemple, cela signifie qu'affecter un
char* à un signed char* requiert
une conversion explicite
de types – un reinterpret_cast,
en fait – même si le type char est signé
sur la plateforme où est réalisée l'affectation
Quelques exemples :
int main()
{
char c = 'A';
signed char sc;
unsigned char uc;
sc = c;
uc = c;
uc = 255;
sc = uc;
c = uc;
char *s = "Coucou";
signed char *scs;
unsigned char *ucs;
scs = reinterpret_cast<signed char*>(s);
ucs = reinterpret_cast<unsigned char*>(s);
}