Mémoire - allocation    Enregistrer au format PDF


par S3cur3D

Déclaration : Exemple du langage C

Quand on programme dans un langage de haut niveau comme C, les variables sont déclarées avec un type. Le type indique la taille des données que l’on veut stocker, ce qui est important pour que le compilateur puisse réserver la place nécessaire au stockage de la variable en mémoire. Nous allons commencer par vous décrire les principaux types du langage C, que nous réutiliserons par la suite :

 les entiers (notés int pour integer) peuvent être stockés sur plus ou moins de mémoire selon le type demandé : les short int sont généralement stockés sur deux octets. Il y a donc 216 valeurs possibles : on peut donc stocker des nombres de -32768 à 32767. Les int sont en général sur 4 octets(-2 147 483 648 à 2 147 483 647) selon les compilateurs. Les long int dépendent eux de l’architecture, ils permettent normalement de pointer l’espace adressable entier, donc 4 octets sur du 32-bits et 8 octets sur du 64-bits. De base, les entiers sont des variables signées (signed, pouvant avoir une valeur négative). On peut aussi utiliser les entiers non-signés. Par exemple, unsigned short int peut stocker des entiers de 0 à 65535.

 les caractères (notés char pour character) sont stockés sur 1 seul octet (256 valeurs possibles représentées par le code ASCII). En pratique, un char n’est pas différent d’un entier sur 1 seul octet.

 les pointeurs sont des variables spéciales. Comme énoncé dans une partie précédente, les pointeurs contiennent uniquement une adresse mémoire, ils sont donc stockés sur un long int, donc 32 bits (4 bytes) pour du x86. Ils sont notés en C par un * devant le nom de la variable. On dit que le pointeur pointe vers une variable quand il contient son adresse.
De plus, les variables peuvent être déclarées dans des tableaux. Un tableau est une juxtaposition de N variables d’un même type. Les tableaux sont plus généralement appellés des buffers et un tableau de caractères est aussi un string (chaîne de caractères). Les pointeurs sont donc plutôt utilisés pour stocker l’adresse de buffers ou de strings. Stocker l’adresse d’un tableau revient à stocker l’adresse du premier élément (l’élément 0).
En C, la syntaxe de déclaration des variables à utiliser est la suivante : type nom_de_la_variable ;
On peut éventuellement donner une valeur dès la déclaration. D’autres types existent, notamment les nombres à virgules flottantes, mais ils ne nous serviront pas par la suite. Afin d’illustrer tout ceci, voici un exemple de bloc de déclaration en langage C :

  1.     short int petit_entier;
  2.     unsigned long int grand_entier_positif=4253643;
  3.     char caractere; //la variable caractere ne pourra stocker qu'un seul caractère
  4.     char mot_de_10_lettres[11];
  5.     char buffer[100];
  6.     char *pointeur_vers_buffer;

Télécharger

Le little endian

Une chose importante avec les processeurs Intel x86 est l’ordre des bytes pour les suites de 4 bytes. Cet ordre est appellé little endian, ce qui veut dire que le dernier byte est le premier. Autrement dit, l’ordre des bytes est inversé : le premier byte est le dernier, le deuxième avant dernier, le troisième deviendra le deuxième et le dernier sera en première position. Ceci est primordial pour l’écriture d’une adresse mémoire. Ainsi, l’adresse héxadécimale 0x12345678 s’écrira en little endian 0x78563412, en inversant bien chacun des 4 bytes. Même s’il n’y pas besoin de savoir l’ordre de stockage des bytes en mémoire pour savoir programmer, ceci devient primordial quand on veut s’attaquer aux buffer overflows ou aux format strings.

La terminaison par le byte nul

Une dernière chose est importante à savoir lors du placement de variables en mémoire. Certains d’entre vous se sont peut-être demandés pourquoi mot_de_10_lettres[11] ne pouvait contenir que 10 lettres si le premier élément était l’élément 0. Effectivement, il y a bien 11 octets de stockage (comme précisé entre crochets) pour cette variable. Mais il faut savoir qu’en mémoire, on repère la fin d’une chaîne de caractères par le byte 0 ou nul byte. En définitive, un programme analysant une chaîne de caractères va lire les bytes présents en mémoire un par un jusqu’à tomber sur le byte 0 où il déclarera la chaîne finie. Ainsi, on peut aussi stocker des mots de 4 caractères dans la variable mot_de_10_lettres sans se soucier de l’espace qui figure après. Dans l’exemple suivant, on montre le stockage des mots "hack" et "hacking024" dans un tableau de 10 caractères (soit 11 bytes) :

0 1 2 3 4 5 6 7 8 9 10
h a c k \0  ?  ?  ?  ?  ?  ?
0 1 2 3 4 5 6 7 8 9 10
h a c k i n g 0 2 4 \n

Attention ! Le byte 0 (\0) n’est pas le nombre 0 (byte 48). Bien sûr, les nombres allant de 0 à 9 sont aussi des caractères. La deuxième chaîne se finit donc bien au byte numéroté 10.

Documentations publiées dans cette rubrique