Sommaire

Promotion entière
Promotion virgule flottante
Conversions implicites
Conversions entre valeurs entières
Conversions entre valeurs réelles (virgule flottante)
Conversions entre entiers et réels
Conversions de pointeurs
Conversions en booléens
Conversions arithmétiques usuelles

Promotion entière

    On peut utiliser n'importe quel caractère (char, unsigned char, signed char), n'importe quel entier court (short, unsigned short), n'importe quelle constante d'un type énumératif, ou un booléen (bool) partout où peut être employé un entier dans une expression, (voir par exemple les constantes entières et leur type), par exemple pour la dimension d'un tableau ou l'indexation. La valeur est convertie en un int si un int peut représenter toutes les valeurs du type d'origine ou un unsigned int dans le cas contraire. Pour les booléens, la valeur false est convertie en 0 et la valeur true en 1. Cette conversion est appelée une promotion entière (voir Norme ISO, 4.5).

Promotion "virgule flottante"

    Une valeur de type float peut être transformée en type double si nécessaire, sans modification. Cette conversion est appelée une promotion "virgule flottante" (voir Norme ISO, 4.6).

Conversions implicites

    Très fréquemment, le compilateur est conduit à "ajuster" certaines valeurs pour les transformer dans un type autre que son type d'origine. C'est en particulier le cas dans deux circonstances particulières :

Conversions entre valeurs entières

    Les conversions entre valeurs entières sont décrites dans la Norme ISO, 4.7.

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 2nn 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.

  1. 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.
  2. 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.
  3. 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.
Conversion entier -> entier signé sd

    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

Conversions entre valeurs réelles (virgule flottante)

    Les conversions entre valeurs réelles sont décrites dans la Norme ISO, 4.8.

    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.

Conversions entre entiers et réels

    Les conversions entre valeurs entières sont décrites dans la Norme ISO, 4.9.

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.

Conversions de pointeurs

    Les conversions entre pointeurs sont décrites dans la Norme ISO, 4.10.

    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

Conversions en booléens

    Les conversions en booléens sont décrites dans la Norme ISO, 4.12.

    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.

Conversions arithmétiques usuelles

    Les conversions implicites occasionnées par les opérateurs arithmétiques sont nombreuses mais toujours conformes au bon sens : elles recherchent toujours à préserver ou permettre le calcul de valeurs sans les altérer. Les plus fréquentes sont les suivantes (voir Norme ISO, 5) :

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.