Aller au contenu

Un soupçon de C

Le langage C est un langage important créé au début des années 1970, fondamental dans les systèmes UNIX. De nombreux langages héritent, d'une façon ou d'une autre, de ce langage C.

Nous introduisons ici quelques principes sur la représentation des entiers avec ce langage.

Exécuter du C

Pour éviter d'avoir à installer sur vos machines le nécessaire pour compiler du C, on utilisera des compilateurs en ligne.

Par exemple:

Ces sites s'ouvrent sur un court exemple de programme. Testez en un.

Entiers codés sur deux octets

On code des entiers sur deux octets. Combien d'entiers distincts peut-on coder?

Rappel

Un octet (en anglais: byte) correspond à 8 bits.
Un bit peut prendre deux valeurs (0 ou 1).

Réponse

Sur deux octets, c'est à dire 16 bits, on dispose de 2^{16} = 65536 codes différents. On peut donc a priori coder 65536 entiers sur ces deux octets.

Le type signed short

En langage C, un entier de type signed short est un entier codé sur 2 octets qui peut prendre des valeurs entre -2^{15} = -32768 et 2^{15}-1 = 32767.

  • A-t-on codé 65536 entiers distincts sur ces deux octets?
Réponse

Oui: 32768 entiers strictement négatifs, plus 32767 entiers strictement positifs et 0: cela fait bien un total de 65536 entiers.

Remarque

Si l'on avait fait le choix de représenter un entier par:

  • le bit à gauche est le bit de signe (1 pour -, 0 pour + par exemple),
  • les bits suivants sont l'écriture en binaire de la valeur absolue de l'entier,

aurait-on coder 65536 entiers sur deux octets?

La réponse est non, pas tout à fait. On aurait bien entendu toujours 2^{16} = 65536 codes différents mais deux codes représenteraient le même entier: 0 serait en effet codé deux fois, une fois par 0000 0000 0000 0000 et une fois par 1000 0000 0000 0000. On aurait en quelque sorte un +0 et un -0.

Un premier code

Exécuter le code C suivant:

#include<stdio.h>

int main() {
    /* On déclare une variable x de type signed short 
    (type décrit ci-dessus dans le paragraphe précédent) 
    puis on lui affecte la valeur 10. */
    signed short x = 10; 
    /* On déclare une variable y de type signed short
    puis on lui affecte la valeur 25. */
    signed short y = 25;
    /* On déclare une variable z de type signed short
    puis on lui affecte la valeur x+y. */
    signed short z = x + y;
    /* On affiche le contenu de z: */
    printf("Somme x + y = %hd", z);
}
  • Qu'obtient-on?
Réponse

On obtient, sans surprise:

Somme x + y = 35
  • Modifier le code pour ajouter 32767 et 1. Qu'obtient-on?
Réponse

Le code:

int main() {

    signed short x = 32767; 
    signed short y = 1;
    signed short z = x + y;
    printf("Somme x + y = %hd", z);
}

On obtient:

Somme x + y = -32768

Vous avez bien vu: il y a un signe - devant le résultat! Nous expliquons cela plus loin.

  • Pouvait-on s'attendre à ce résultat?
Réponse

Comme la somme demandée dépasse l'entier maximal codable dans ce format, on doit s'attendre à un résultat qui ne soit pas 32768.

Mais pourquoi l'opposé? Nous expliquerons cela dans la suite en entrant un peu dans le détail du codage en machine de ces nombres.

Important

On aurait pu s'attendre à un message d'erreur du type "dépassement de capacité". Sans un tel message, on voit que c'est au programmeur de gérer ce type de dépassement ce qui n'est pas sans poser problème (bugs...)

Vous pouvez lire ici un exemple, heureusement sans conséquence, d'un tel dépassement de capacité (vous pourrez aussi remarquer en passant que l'auteur de l'article n'a pas de formation informatique: il a visiblement confondu octet et bit).

Et ici un autre exemple, qui lui a eu une conséquence au coût élevé.

Un type sur 4 octets

On définit un type "entier signé" sur 4 octets.

  • Combien d'entiers distincts peut-on définir sur 4 octets?
  • Les entiers codés, comme pour le type signed short du langage C, sont les entiers d'un intervalle [ emin; emax] comportant autant d'entiers strictement négatifs que d'entiers positifs ou nuls. Que valent emin et emax? En d'autres termes, quel est l'entier (positif) le plus grand codé dans ce type? Et le plus petit (négatif)?
Sur 4 octets

Sur 4 octets, c'est à dire sur 32 bits, on code 2^{32} = 4 294 967 296 entiers distincts.

Plage des entiers codés

Le plus petit négatif est -2^{31} = -2 147 483 648.
Le plus grand positif est 2^{31}-1 = 2 147 483 647.