1.2. Les types prédéfinis du C/C++

Il y a plusieurs types prédéfinis. Ce sont :

Les types entiers (int) peuvent être caractérisés d'un des mots-clés long ou short. Ces mots-clés permettent de modifier la taille du type, c'est-à-dire la plage de valeurs qu'ils peuvent couvrir. De même, les réels en double précision peuvent être qualifiés du mot-clé long, ce qui augmente leur plage de valeurs. On ne peut pas utiliser le mot-clé short avec les double. On dispose donc de types additionnels :

La taille des types n'est spécifiée dans aucune norme, sauf pour le type char. En revanche, les inégalités suivantes sont toujours vérifiées :

char ≤ short int ≤ int ≤ long int float ≤ double ≤ long double
où l'opérateur « <= » signifie ici « a une plage de valeur plus petite ou égale que ». La taille des caractères de type char est toujours de un octet.

Les types char et int peuvent être signés ou non. Un nombre signé peut être négatif, pas un nombre non signé. Lorsqu'un nombre est signé, la valeur absolue du plus grand nombre représentable est plus petite. Par défaut, un nombre est signé (sauf les type char et wchar_t, qui peuvent être soit signés, soit non signés, selon le compilateur utilisé). Pour préciser qu'un nombre n'est pas signé, il faut utiliser le mot-clé unsigned. Pour préciser qu'un nombre est signé, on peut utiliser le mot-clé signed. Ces mots-clés peuvent être intervertis librement avec les mots-clés long et short.

Exemple 1-3. Types signés et non signés

unsigned char
signed char
unsigned int
signed int
unsigned long int
long unsigned int

Les valeurs accessibles avec les nombres signés ne sont pas les mêmes que celles accessibles avec les nombres non signés. En effet, un bit est utilisé pour le signe dans les nombres signés. Par exemple, puisque le type char est codé sur 8 bits, on peut coder les nombres allant de 0 à 256 avec ce type en non signé (il y a 8 chiffres binaires, chacun peut valoir 0 ou 1, on a donc 2 puissance 8 combinaisons possibles, ce qui fait 256). En signé, les valeurs s'étendent de -128 à 127 (un des chiffres binaires est utilisé pour le signe, il en reste 7 pour coder le nombre, donc il reste 128 possibilités dans les positifs comme dans les négatifs. 0 est considéré comme positif. En tout, il y a autant de possibilités.).

Le type int doit être capable de représenter les entiers utilisés par la machine sur laquelle le programme tournera. Par exemple, sur les machines 16 bits ils sont codés sur 16 bits (les valeurs accessibles vont donc de -32768 à 32768, ou de 0 à 65535 si l'entier n'est pas signé). C'est le cas sur les PC en mode réel (c'est-à-dire sous DOS) et sous Windows 3.x. Sur les machines fonctionnant en 32 bits, le type int est stocké sur 32 bits : l'espace des valeurs disponibles est donc 65536 fois plus large. C'est le cas sur les PC en mode protégé 32 bits (Windows 95 ou NT, DOS Extender, Linux), sur la plupart des machines UNIX et sur les Macintosh. Sur les machines 64 bits, le type int est 64 bits (DEC Alpha par exemple). On constate donc que la portabilité des types de base est très aléatoire. En pratique cependant, ils ont souvent la même taille pour toutes les machines 32 bits (la majorité). Sur ces machines, les entiers longs sont codés la plupart du temps sur 32 bits et les entiers courts sur 16 bits. Les caractères sont souvent codés sur 8 bits. Le type wchar_t est équivalent à l'un des types entiers, il est souvent codé sur 16 bits. Enfin, le type float est généralement codé sur 4 octets et les types double et long double sont identiques et codés sur 8 octets.

Le C++ (et le C++ uniquement) considère le type char comme le type de base des caractères. Les caractères n'ont pas de notion de signe associée. Cependant, les caractères peuvent être considérés comme des entiers à tout instant, mais il n'est pas précisé si ce type est signé ou non. Cela dépend du compilateur. L'interprétation du type char en tant que type intégral n'est pas le comportement de base du C++, par conséquent, le langage distingue les versions signées et non signées de ce type de la version dont le signe n'est pas spécifié. Cela signifie que le compilateur traite les types char, unsigned char et signed char comme des types différents. Cette distinction n'a pas lieu d'être au niveau des plages de valeurs si l'on connaît le signe du type char, mais elle est très importante dans la détermination de la signature des fonctions (la signature des fonctions sera définie plus loin dans ce cours).

Si l'on veut faire du code portable (c'est-à-dire qui compilera et fonctionnera sans modification du programme sur tous les ordinateurs), il faut utiliser des types de données qui donneront les mêmes intervalles de valeurs sur tous les ordinateurs. Il est donc recommandé de définir ses propres types (par exemple int8, int16, int32) dont la taille et le signe seront fixe. Lorsque le programme devra être porté, seule la définition de ces types sera à changer, pas le programme. En pratique, si l'on veut faire du code portable entre les machines 16 bits et les machines 32 bits, on ne devra pas utiliser le type int seul : il faudra toujours indiquer la taille de l'entier utilisé : short (16 bits) ou long (32 bits).