Conversions entre valeurs entièresConversions arithmétiques usuelles
Conversions entre valeurs réelles (virgule flottante)
Conversions entre entiers et réels
Conversions de pointeurs
Conversions en booléens
int i;
char Carac = i + '0'; double Euro = Centimes / 10.0; |
Avant de pouvoir faire l'opération, le compilateur ramène les deux opérandes au même type par promotion, (transformation de '0' en int) ou par conversion en utilisant les règles énoncées ci-dessous.
double sqrt (double d); // renvoie la racine carrée de d
float Surface; //... float Rayon = sqrt (Surface / 3.141592f); |
La constante 3.141592f avec le suffixe f (ou F) représente la valeur de pi de type float. Surface étant de ce type, la division ne nécessite pas de conversion implicite. Cependant, le résultat de cette opération est de type float et doit donc être converti avant d'être passé en paramètre de sqrt(). Le résultat sera lui-même reconverti en float lors de l'affectation. Ces différentes conversions entre les types de base utilisent les règles énoncées ci-dessous.
Autre exemple :
void f (const string & Str);
//... f ("Coucou"); |
Dans ce cas, il ne s'agit pas de conversions de même nature.
Le compilateur ne trouvant pas de fonction f() dont la signature comporte un paramètre de type const char * const, essaie d'adapter ce paramètre pour pouvoir utiliser la seule fonction qu'il connaît ici.
Il lui faut donc savoir transformer un const char * const en string.
Il trouve dans la classe string un constructeur qui fait cette transformation.
Il appelle donc de sa propre initiative ce constructeur et compile en fait l'instruction :
f (string ("Coucou")); |
Ceci n'est possible que parce que ce constructeur n'a pas le qualificatif explicit (qui est justement destiné à interdire les conversions implicites de ce genre).
Autre exemple :
void g (int D);
//... class CDuree; // comporte une durée en secondes, ainsi que // sa représentation en jours, heures, minutes et secondes CDuree Duree (3601); g (Duree); |
Dans ce cas, la "classe" int ne possède pas de constructeur à partir d'un objet CDuree.
En revanche, celle-ci peut posséder l'opérateur de conversion de type int().
L'instruction effectivement compilée est la suivante :
g (int (D)); |
Conversion entier signé ss -> entier non signé nsd
Si le type destination est non signé, la valeur résultante est le plus petit entier non signé congru à l'entier d'origine (modulo 2n où n est le nombre de bits utilisés pour représenter l'entier non signé. Si la représentation interne des entiers utilise le complément à 2, la conversion est virtuelle car la représentation binaire est identique.
Conversion entier -> entier signé sd
- entiers source et destination sans changement du nombre de bits.
Supposons par exemple que ss et nsd sont codés sur 1 octet (n = 8, donc 2n = 256).
Si ss = 2 (0000 0010) => nsd = 2 (0000 0010) : la conversion d'un entier signé positif en entier non signé n'a évidemment aucun effet.
Si ss = 127 (0111 1111 : valeur maximale = 28 - 1) => nsd = 127 (0111 1111) : idem.
Si ss = -2 (1111 1110) => nsd = -2 mod 256 = (-2 + 256) mod 256 = 254 (1111 1110) : la conversion d'un entier signé négatif en entier non signé est donc virtuelle.
Si ss = -127 (1000 0001) => nsd = -127 mod 256 = (-127 + 256) mod 256 = 129 (1000 0001) : idem.- entiers source sur 2 octets et destination sur 1 octet (n = 8, donc 2n = 256).
Si ss = 2 (0000 0000 000 0010) => nsd = 2 (0000 0010) : la conversion d'un entier signé positif en entier non signé tronque l'octet de fort poids.
Si ss = 32767 (0111 1111 1111 1111 : valeur maximale = 216 - 1) => nsd = (216 - 1) mod 256 = (216 - 1 + 256) mod 256 = 255 (1111 1111) : idem. Il y a troncature de la valeur.
Si ss = -2 (1111 1111 1111 1110) => nsd = -2 mod 256 = (-2 + 256) mod 256 = 254 (1111 1110) : L'octet de fort poids est tronqué mais la valeur résultante est juste.
Si ss = -32767 (1000 0000 0000 0001 : valeur minimale = -(216 - 1) => nsd = -(216 - 1) mod 256 = (-216) mod 256 + 1 mod 256 = 1 (0000 0001) : troncature de l'octet de fort poids et valeur résultante fausse.- entiers source sur 1 octet et destination sur 2 octets (n = 16, donc 2n = 67536).
Si ss = 2 (0000 0010) => nsd = 2 (0000 0000 0000 0010) : la conversion d'un entier signé positif en entier non signé étend le bit de signe à l'octet de fort poids.
Si ss = 127 (0111 1111 : valeur maximale = 28 - 1) => nsd = (28 - 1) mod 67536 = 28 - 1 = 255 (0000 0000 0111 1111) : idem.
Si ss = -2 (1111 1110) => nsd = (-2 + 67536) mod 67536 = 67534 (1111 1111 1111 1110) : L'octet de fort poids est l'extension du signe, mais la valeur résultante est fausse.
Si ss = -127 (1000 0001 : valeur minimale = -(28 - 1) => nsd = (-127 + 67536) mod 67536 = 67409 (1111 1111 1000 0001) : idem.Si le type de l'entier de destination est signé, la valeur est inchangée si le type destinataire peut la représenter, sinon le résultat dépend de l'implémentation (=> à éviter !) Attention, même si l'entier source est non signé, il dispose d'un bit significatif de plus que l'entier récepteur, dans lequel un bit est utilisé comme "bit de signe".
Conversion booléen -> entier
La valeur false est convertie en 0, la valeur true est convertie en 1.
Conversion entier -> booléen : voir Conversions en booléens
Lorsque le type récepteur a plus de bits significatifs que le type émetteur, la conversion ne modifie pas la valeur numérique.
Lorsque le type récepteur a moins de bits significatifs que le type émetteur (par exemple une conversion double --> float, ou long double --> double), seule la partie fractionnaire est tronquée. La valeur peut ne pas être affectée si la caractéristique (exposant) peut être représentée exactement dans le type destination et si la partie tronquée de la mantisse (partie décimale) est exclusivement constituée de bits non significatifs (par exemple, 0,5 en binaire est codé 0,100000...0 exactement) et . La troncature de la mantisse n'a alors aucun effet. Si la mantisse doit être tronquée, cela signifie que la valeur réelle du type source est entre deux valeurs consécutives du type destination. La valeur résultante est arrondie par défaut ou par excès selon l'implémentation. Si la caractéristique doit être tronquée, le résultat est indéfini.
conversion type réel --> type entier
La partie fractionnaire du réel est supprimée. Si la partie entière ne peut être stockée dans l'entier destinataire, le résultat est indéfini.
La conversion type réel --> type booléen est présentée plus bas.conversion type entier --> type réel
Le résultat est exact si possible. Si la mantisse doit être tronquée, cela signifie que la valeur entière du type source est entre deux valeurs consécutives du type destination. La valeur résultante est arrondie par défaut ou par excès selon l'implémentation. Si la caractéristique doit être tronquée, le résultat est indéfini.La valeur booléenne false est convertie en 0.0, la valeur true est convertie en 1.0.
Un pointeur constant nul est une expression constante entière dont la valeur est nulle (zéro). Un pointeur constant nul peut être converti en type pointeur, le résultat est la valeur "pointeur nul" de ce type, elle est distincte de toute autre valeur de type pointeur sur objet ou pointeur sur fonction. Deux pointeurs de valeur nulle de même type peuvent subir une comparaison d'égalité.
Par exemple :
char * PChar1;
pChar1 = 0; // conversion de 0 en "pointeur nul" de caractère char * PChar2 = pChar1; int * pInt; pInt = 0; // conversion de 0 en "pointeur nul" d'entier if (pChar1 == pChar2) // autorisé : comparaison de pointeurs de mêmes types if (pChar1 == pInt) // interdit : comparaison de pointeurs de types différents |
Toute valeur arithmétique (entière ou réelle), tout pointeur, ou constante de type énumératif peut être convertie en booléen, false si elle est nulle, true dans tous les autres cas.
Si l'un des opérandes est de type long double, l'autre sera converti en long double,
sinon, si l'un des opérandes est de type double, l'autre sera converti en double,
sinon, si l'un des opérandes est de type float, l'autre sera converti en float,
sinon, les promotions entières seront effectuées sur les deux opérandes.Puis,
si l'un des opérandes est de type unsigned long,
alors
l'autre sera converti en unsigned long,
sinon
si l'un des opérandes est de type long int et l'autre de type unsigned int,
alors
si un long int peut représenter toutes les valeurs d'un unsigned int,
alors
l'unsigned long int sera converti en long int
sinon
les deux opérandes seront convertis en unsigned long int
sinon,
si l'un des opérandes est de type long int,
alors
convertir l'autre en long int,
sinon
si l'un des opérandes est de type unsigned
alors
convertir l'autre en unsigned unsigned
sinon
le seul cas restant est celui où les deux opérandes sont de type int.