Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Mémoire, octets et adresses en C

Après cette leçon: Je peux dire quelle taille a une variable en C et où elle se place en mémoire.

Leçon de 55 min5 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Six octets de données, douze octets en mémoire

Le langage C range chaque variable dans des cases de mémoire appelées octets, et le programmeur doit savoir combien elle en prend. Connaître la taille d’une variable et son adresse explique des erreurs qui n’affichent aucun message.

Un logiciel de caisse garde un million de lignes de vente. Chaque ligne a un code d’un octet, une quantité de quatre octets et un rayon d’un octet. Six octets, donc six mégaoctets ? Non : douze. Cette leçon explique pourquoi.

À la fin de cette leçon

Remarque

Je peux dire quelle taille a une variable en C et où elle se place en mémoire.

Mots-clés

MotCe que ça veut direExemple
Octetune case de mémoire qui contient un nombre de 0 à 255
Typece qui dit combien d’octets prend une variableint
Adressele numéro d’un octet dans la mémoire
Alignementla règle qui place une variable sur un multiple de sa taille
Remplissageles octets perdus que le compilateur ajoute pour aligner
sizeofl’opérateur qui donne la taille en octetssizeof(int)

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Chaque type a une taille en octets

Un type dit à la fois quelle sorte de valeur une variable contient et combien d’octets elle prend. Le mot sizeof donne cette taille, et le compilateur la calcule avant même que le programme tourne.

Le type char prend un octet, short deux, int quatre et double huit. Le type long dépend du système : huit octets sous Linux, quatre sous d’autres systèmes. Demandez-le toujours à sizeof.

Un programme qui affiche des tailles

Code: c
#include <stdio.h>

int main(void) {
    printf("%zu %zu %zu %zu\n", sizeof(char), sizeof(short),
           sizeof(int), sizeof(double));
    return 0;
}

Créer un dossier de travail

Commande
mkdir -p ~/c && cd ~/c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le programme dans un fichier

Commande
printf '#include <stdio.h>\nint main(void) {\n    printf("%%zu %%zu %%zu %%zu\\n", sizeof(char), sizeof(short), sizeof(int), sizeof(double));\n    return 0;\n}\n' > tailles.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compiler et lancer le programme

Commande
gcc -Wall -o tailles tailles.c && ./tailles

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Exemple travaillé : ce que le programme a affiché

TypeTailleNombre de valeurs possibles
char1 octet256
short2 octets65 536
int4 octetsenviron 4,3 milliards
double8 octetsun nombre à virgule, très grand

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Une adresse est le numéro d’un octet

Imaginez la mémoire comme une longue rangée de casiers numérotés. Chaque casier est un octet, et son numéro est son adresse. Un int occupe quatre casiers qui se suivent, et son adresse est celle du premier.

Les adresses s’écrivent en hexadécimal et changent d’un lancement à l’autre. Les leçons ne citent donc jamais une adresse : elles décrivent sa forme.

Exemple travaillé : l’entier 258 dans quatre casiers

CasierContenu en hexadécimalContenu en décimal
début + 0022
début + 1011
début + 2000
début + 3000

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

L’octet de poids faible vient en premier

Le nombre 258 vaut 1 × 256 + 2. Les processeurs courants rangent d’abord l’octet qui pèse le moins, ici 2, puis celui qui pèse 256, ici 1. On dit petit-boutiste (little endian en anglais).

Lire ces quatre octets dans l’ordre inverse donnerait un tout autre nombre.

Le compilateur ajoute du remplissage

Un processeur lit vite un int posé sur une adresse multiple de quatre. Le compilateur respecte donc l’alignement : il saute quelques octets pour placer chaque champ d’une structure sur un multiple de sa taille. Ces octets perdus forment le remplissage.

La structure a ci-dessous a un char, un int puis un char. La structure b a les mêmes champs dans un autre ordre.

Deux structures avec les mêmes champs

Code: c
struct a { char c; int n; char d; };
struct b { int n; char c; char d; };

Exemple travaillé : où chaque champ se place

Structure aDécalageOctets
char c01, puis 3 de remplissage
int n44
char d81, puis 3 de remplissage final
Total12

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Écrire le programme des structures

Commande
printf '#include <stdio.h>\n#include <stddef.h>\nstruct a { char c; int n; char d; };\nstruct b { int n; char c; char d; };\nint main(void) {\n    printf("%%zu %%zu\\n", sizeof(struct a), sizeof(struct b));\n    printf("%%zu %%zu\\n", offsetof(struct a, n), offsetof(struct a, d));\n    return 0;\n}\n' > champs.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Afficher les tailles et les décalages

Commande
gcc -Wall -o champs champs.c && ./champs

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Erreur fréquente

Attention

Beaucoup de gens pensent que la taille d’une structure est la somme de ses champs. C’est faux dès qu’un champ doit être aligné. Rangez les champs du plus grand au plus petit pour perdre moins d’octets : ici b prend 8 octets, a en prend 12.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.