Previous Up Next

3  Différents sens pour les mêmes nombres

Comme vous l’avez vu en cours de codage, les systèmes informatiques ne traitent que des nombres, mais ces nombres (binaires) peuvent prendre des sens très différents selon le rôle que l’on veut leur faire jouer. La fonction de la librairie standard putchar() prend un int pour produire un caractère sur la sortie standard. Cependant d’autres affichage de cette même valeur «entière» peuvent être utiles. On peut par exemlpe vouloir d’afficher la suite de caractères entre ’0’ et ’9’ qui représentent le nombre en décimal, ou en hexadécimal...

Dans la série d’exercices qui suit, il vous est demandé d’implémenter une série de fonctions. Implémentez ces fonctions dans un fichier numbers.c. Dans ce même fichier, fournissez une fonction int main() dans laquelle vous ferez des appels aux fonctions implémentées en vue d’en tester le bon fonctionnement.

3.1  Afficher des caractères


Exercice 23
 (Afficher un chiffre (décimal))   Proposez une implémentation de la fonction de prototype
int put_digit(int d);
qui affiche le chiffre (digit) d. Ainsi :

Exercice 24
 (Afficher un chiffre hexadécimal)   De même proposez une fonction int put_hdigit(int h); qui affiche un nombre h sous la forme d’un caractère hexadécimal. h est donc une valeur entre 0 et 15 et le code ASCII produit est donc :

Vous pouvez maintenant afficher des caractères ASCII et des chiffres hexadécimaux.

Il est parfois utile de pouvoir consulter la table des codes ASCII. Un simple programme peut afficher cette table :

--  -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F
0-  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
1-  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
2-      !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /
3-   0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?
4-   @  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O
...  
E-  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
F-  .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..

Quand le caractère ASCII n’est pas affichable, les caractères .. sont produits (les caractères ASCII affichables ont une valeur comprise entre 32 et 126, consultez par exemple la page de manuel man ascii).


Exercice 25
 (Table des codes ASCII)   Proposez une fonction void print_ascii_table() qui affiche la table des codes ASCII, conformément à l’exemple donné ci-dessus. Cette fonction fera exclusivement appel à putchar() et à nos fonctions newline() et put_hdigit().

Vous ajouterez cette fonction au fichier numbers.c et y ferez appel dans le main() afin de la tester.

Les entiers en C   ...on fait le point...

Notez que comme int n’est pas un entier quelconque mais un mot mémoire d ne peut pas être «arbitrairement grand». Sur votre machine, N est défini à 32 donc int peut représenter 4.294.967.296 codes distincts. Les microprocesseurs utilisent le codage des nombres signés en «complément à deux» (cf. Cours de Codage, chapitre 1). Ce codage permet de représenter des nombres entre -2.147.483.648 et 2.147.483.647.

Cette asymétrie entre le plus petit et le plus grand int a notament comme conséquence qu’il n’est pas possible de calculer la valeur absolue du plus petit int.

3.2  Afficher des nombres

Les fonctions putchar(), put_digit() et put_hdigit() affichent un caractère correspond à la valeur int reçue en paramètre. La fonction putchar() permet d’afficher un caractère en donnant un int correspondant à son code ASCII (ou UTF-8), la fonction put_digit() affiche le chiffre (dont un caractère) correspondant à la valeur de type int donnée, etc.

Nous allons maintenant définir des fonctions qui considèrent le mot mémoire correspondant à un int (cf l’encart Les entiers en C) comme une valeur entière qu’il conviendra d’écrire en décimal, hexadécimal, binaire, etc. Nous allons donc afficher des séries de caractères qui représentent les chiffres qui composent le nombre, éventuellement précédés d’un premier caractère pour indiquer le signe du nombre.


Exercice 26
 (Afficher un nombre - décimal)   Donnez la définition de la fonction
int putdec(int d);
qui affiche les chiffres de l’écriture décimale de la valeur d, au besoin, précédé d’un signe négatif, et sans afficher de ’0’ inutiles à gauche du nombre.

Cette fonction retourne normalement 0, -1 en cas d’erreur.

Nous avons vu que les opérations arithmétiques du langage C sur des valeurs du type int sont traduites en opérations élémentaires du microprocesseur. De plus, le microprocesseur travaille en «complément à deux». Enfin, le type int correspond à un mot mémoire de 32 bits. Ces éléments sont a prendre en compte pour comprendre comment est calculé l’opposé de -2.147.483.648.


Exercice 27
 (L’opposé de -2.147.483.648)   Modifiez la fonction main() de numbers.c et saisissez le code suivant :
int main() 
{
    int i=-2147483648;
    putdec(-i);
    return 0;
}
Qu’affiche maintennant l’exécution de ce programme ? Et surtout... pourquoi ?

Exercice 28
 (Afficher un nombre binaire)   Proposez une fonction putbin(int b) qui affiche un nombre b en paramètre sous la forme d’une série de 0 et de 1.

Notez qu’il est possible de déterminer la valeur du bit de poids faible (ou de plusieurs bit) d’un nombre en utilisant l’opérateur &. Utilisez les opérateurs >> pour décaler les bits d’un nombre vers la droite...

Comme pour la fonction putdec(), il est inutile, d’afficher les 0 à gauche du nombre. Et comme pour putdec(), la fonction retourne 0 si le nombre a été correctement affiché sur la sortie standard, -1 sinon.


Exercice 29
 (Affichage hexadécimal)   Proposez une fonction int puthex(int h) qui prend un nombre h en paramètre et qui produit sur la sortie standard une série de code ASCII représentant ce nombre h sous forme hexadécimale.

Pour vous aider, observez qu’un mot mémoire de 32 bits est composé de 8 quartets de 4 bits. Chaque quartet est un chiffre hexadécimal du nombre. Utilisez ici encore, avantageusement les opérateurs >> et &.

Réalisez maintenant une nouvelle version de la fonction main() de numbers.c :

int put_test_line(int n)
{
    putchar('t');
    putchar('e');
    putchar('s');
    putchar('t');
    putchar(' ');
    putchar('#');
    putdec(n);
    putchar(':');

    return 0;
}

int main()
{
    int i=-2147483648;
    put_test_line(1); putdec(214); newline();
    put_test_line(2); putdec(-74); newline();
    put_test_line(3); putdec(1); newline();
    put_test_line(4); putdec(-1); newline();
    put_test_line(5); putdec(0); newline();
    put_test_line(6); putdec(2147483647); newline();
    put_test_line(7); putdec(-2147483648); newline();
    put_test_line(8); putdec(-(-2147483648)); newline();
    put_test_line(9); puthex(0); newline();
    put_test_line(10); puthex(10); newline();
    put_test_line(11); puthex(16); newline();
    put_test_line(12); puthex(2147483647); newline();
    put_test_line(13); puthex(-2147483648); newline();
    put_test_line(14); puthex(0xCAFEBABE); newline();
    put_test_line(15); puthex(-1); newline();
    put_test_line(16); putbin(0); newline();
    put_test_line(17); putbin(1); newline();
    put_test_line(18); putbin(-1); newline();
    put_test_line(19); putbin(2147483647); newline();
    put_test_line(20); putbin(-2147483648); newline();

    return 0;
}

Vous trouverez ce code dans le fichier numbers-test.c du dépôt Git.


Exercice 30
 (Tester vos programmes)   Pour valider le bon fonctionnement de ce programme, nous vous donnons un fichier de trace correct que nos avons produit. Voyez numbers-out.txt du dépôt Git.

Vous aller utiliser la commande diff pour comparer la trace attendue par le programme précédent.

Si votre programme n’a pas le comportement attendu, c’est-à-dire si ce qu’il affiche diffère de la trace proposée... corrigez le !


Previous Up Next