Comment pouvez-vous faire la différence entre ASCII en binaire et la même décimale en binaire?


Réponse 1:

En général, vous ne pouvez pas, pas par les seuls bits. Par exemple, le numéro 00111001 en binaire: il pourrait bien s'agir du nombre 57, mais il pourrait également s'agir du chiffre ASCII «9».

Cela dit, dans la pratique, vous pouvez souvent faire la différence. Parce que vous aurez une idée de la valeur avec laquelle vous travaillez. Considérez la fonction C suivante, qui contient un bogue flagrant:

int print (int n) {char buf [1]; int i; i = 3 * n + 2; sprintf (buf, "% i \ n", i); met (buf); return i; }

Il calcule, pour chaque entier n, la valeur 3 * n + 2, vide cette valeur dans la console et renvoie la valeur sous forme d'entier. Cependant, vous pouvez remarquer lors du test de cette fonction, que si l'entrée est, disons 9, elle imprime le résultat correct 29 sur la console. Mais il renverra la mauvaise valeur, dans ce cas la valeur 57. Et cela peut vous donner un indice sur ce qui se passe ici, car vous remarquerez que 57 est la représentation ASCII du nombre 9, et cela se trouve être le dernier chiffre du résultat.

Vous effectuez ensuite une expérimentation et constatez que cela est vrai chaque fois que le résultat est un nombre à 2 chiffres. Par exemple, avec n = 5, le résultat devrait être 17, mais à la place, le résultat est 55, la représentation ASCII du chiffre «7».

Et lorsque le résultat comporte plus de 2 chiffres, le résultat est encore plus étrange. Par exemple, avec n = 50, le résultat correct 152 est sauvegardé sur la console, mais la valeur de retour est 12853 en décimal ou 0x3235 en hexadécimal. Vous remarquerez peut-être qu'il s'agit de la représentation ASCII de la chaîne «25», ou des deux derniers chiffres du résultat, dans l'ordre inverse!

Alors, que se passe-t-il ici? Notez que le tampon de caractères n'a de place que pour un seul caractère! La fonction sprintf () en C ne vérifie pas les dépassements de tampon, elle écrit donc avec plaisir sa sortie dans la mémoire pointée par buf, écrasant les octets suivant immédiatement les octets réservés à buf si buf est trop petit. Dans ce cas, ce sont les octets réservés à l'entier i, et ils sont écrasés. Et puisque la valeur de i est ensuite utilisée comme valeur de retour de cette fonction, la valeur de retour sera incorrecte.

Une seule question demeure: pourquoi la valeur de retour contient-elle les derniers chiffres ASCII du résultat, mais dans l'ordre inverse? Cela se produit parce que (en supposant que vous travaillez sur un PC) les octets d'un entier sont stockés «dans le mauvais sens». Par exemple, l'entier 32 bits 0x12345678 est stocké sous forme d'octets 0x78 0x56 0x34 0x12 en mémoire.

Ainsi, lorsque l'entrée est n = 50, le premier chiffre du résultat sera stocké dans buf, tandis que les deuxième et troisième chiffres du résultat se retrouveront dans i, qui deviendra alors, en octets, 0x35 0x32 0x00 0x00. Et cela représente la valeur 0x3235 = 12853 en décimal lorsqu'il est interprété comme un nombre 32 bits.

En conclusion: si vous essayez réellement ceci sur votre machine, les résultats peuvent très bien être différents, car les effets de ce type de bogue dépendent fortement du fonctionnement interne de votre machine et de votre compilateur. Par exemple, un smartphone stockera le plus souvent ses octets dans le bon ordre, vous obtiendrez donc un numéro différent. Et votre compilateur peut très bien réserver plus d'un octet pour buf en raison de problèmes d'alignement de la mémoire, ou il peut stocker buf et i dans l'autre sens (i d'abord en mémoire, puis buf). Ou il peut optimiser i away en ne conservant le résultat que dans un registre CPU. Dans ce cas, le résultat sera correct mais quelque chose d'autre en mémoire sera corrompu.

En général, si les programmes contiennent des bogues comme celui-ci, tous les paris sont sur ce qui se passera réellement.


Réponse 2:

Si 48 est la représentation ASCII du nombre zéro et 57 la représentation ASCII de neuf, alors le quartet le moins significatif est le chiffre réel représenté:

0000 0000-0011 0000 = 32 + 16 + 0 = 48

0000 0001-0011 0001

0000 0010-0011 0010

0000 0011-0011 0011

0000 0100-0011 0100

0000 0101-0011 0101

0000 0110-0011 0110

0000 0111-0011 0111

0000 1000-0011 1000

0000 1001-0011 1001 = 32 + 16 + 8 + 1 = 57

ou simplement; soustrayez 48 pour vous donner le nombre.