Jouons avec les unsigned int en C

Mixer des entiers signés (int) et non signés (unsigned int) en C ou C++ est une bonne manière de se tirer dans le pied…

Petite démonstration :

[c]
#include <stdio.h>

int main()
{
  int ref = -6;
  int a = 4;
  unsigned int b = 4;

  int x = 0;
  unsigned int y = 0;

  if (ref + a == ref + b)
    printf("ref + a == ref + b\
");

  printf("ref + a = 0x%x\
", ref + a);
  printf("ref + b = 0x%x\
", ref + b);

  if (ref + a > x)
    printf("ref + a > x\
");
  if (ref + b > x)
    printf("ref + b > x\
");

  if (ref + a > y)
    printf("ref + a > y\
");
  if (ref + b > y)
    printf("ref + b > y\
");

  if (ref + a > 0)
    printf("ref + a > 0\
");
  if (ref + b > 0)
    printf("ref + b > 0\
");
}

Enregistrons le tout dans un fichier nommé test.c, puis compilons avec la commande suivante :

$ g++ -Wall -Wextra test.c -o test
test.c: In function ‘int main()':
test.c:12: attention : comparaison entre des expressions entières signée et non signée
test.c:20: attention : comparaison entre des expressions entières signée et non signée
test.c:23: attention : comparaison entre des expressions entières signée et non signée

Notons les jolis avertissements qui s’affichent pour les lignes 12, 20 et 23 et testons maintenant l’exécution :

$ ./test
ref + a == ref + b
ref + a = 0xfffffffe
ref + b = 0xfffffffe
ref + b > x
ref + a > y
ref + b > y
ref + b > 0

Le test (ref + a == ref + b) retourne vrai, et en effet, comme on peut le voir en dessous, la représentation binaire (ici en hexadécimale) est identique dans les 2 cas. Tous les autres tests auraient dû échouer : -6 + 4 == -2, ce qui est inférieur à 0. On est tous d’accord ;)

Et pourtant, à chaque fois qu’un entier non signé était présent dans l’expression evaluée, le résultat s’explique mais est pour le moins surprenant. 4 résultats surprenants, mais seulement 2 avertissements correspondants…

Bon débuggage…

PS : l’avertissement à la ligne 12 concerne l’évaluation de ref + a == ref + b.