Les surprises des conversions

D'une manière générale, les conversions sont un mécanisme qui fonctionne à la satisfaction du programmeur. Il y a cependant une situation où cela peut donner des résultats surprenants : quand on réalise une comparaison entre entiers signés et entiers non signés. Par exemple, le programme suivant :
int main(void)
{
unsigned int i = 0;

if (i < -1 )
   printf("Bizarre, bizarre ...\n");
   else printf ("Tout semble normal\n");
}
imprimera le message Bizarre, bizarre ..., pouvant laisser croire que pour le langage C, $0$ est inférieur à $-1$.

L'explication est la suivante : l'opérateur $<$ a un opérande de type unsigned int (la variable i), et un autre opérande de type int (la constante -1). D'après le tableau des conversions donné ci-dessus, on voit que dans un tel cas, les opérandes sont convertis en unsigned int. Le compilateur génère donc une comparaison non signée entre 0 et 4294967295 (puisque -1 = 0xffffffff = 4294967295), d'où le résultat.

Pour que tout rentre dans l'ordre, il suffit d'utiliser l'opérateur de conversion pour prévenir le compilateur de ce qu'on veut faire :

int main(void)
{
unsigned int i = 0;

if ((int) i < -1 )    /*   comparaison entre deux int   */
   printf("Bizarre, bizarre ...\n");
   else printf ("Tout semble normal\n");
}

Là où tout se complique c'est qu'on peut utiliser des entiers non signés sans le savoir ! Considérons le programme suivant :

int main(void)
{
if (sizeof(int) < -1)
   printf("Bizarre, bizarre ...\n");
else printf ("Tout semble normal\n");
}
le lecteur a sans doute deviné qu'il va imprimer le message Bizarre, bizarre ..., et cependant les entiers n'ont pas une longueur négative ! L'explication est la suivante : l'opérateur sizeof rend une valeur dont le type est non signé. Voici ce que dit exactement la norme : « La valeur du résultat [ de sizeof ] dépend de l'implémentation, et son type (un type entier non signé) est size_t qui est définit dans le fichier d'include stddef.h ». Dans notre exemple, le compilateur a généré une comparaison non signée entre 4 (sizeof(int)) et $4\:294\:967\:295$, d'où le résultat.



Sous-sections
Matthieu Moy 2017-02-08