LU1IN002 : Éléments de programmation 2
Cours 2
Code binaire, mémoire, pointeurs
Cours : Jean-Lou Desbarbieux, François Bouchet,
Mathilde Carpentier
et toute l’équipe de l’UE
LU1IN002 Sorbonne Université 2023/2024
Sections : ScFO 21 - CMI Méca - SPH 2
Architecture d’un ordinateur
Architecture d’un ordinateur
Bus adresses
Unité de Pile
commande
Registres
Tas
Données
Unité
arithmétique Programme
et logique
Unité de controle Unité mémoire
Bus données
≈ micro processeur
La mémoire
▶ Unité de base = l’octet
1 octet = 8 bits
01010001 Par exemple, pour une entier non signé sur un
octet (unsigned char)
▶ Plusieurs octets sont traités en même temps par le processeur.
32 bits = 4 octets : 11010001010100011101100101010101
64 bits = 8 octets :
1101000101010001110110010101010111010001010100011101100101010101
▶ Des informations complexes y sont stockées : des instructions,
des données (sur plusieurs octets)
Information binaire
5V, 3.3V, 1.65V (I) (I)
Deux états de tension électrique :
0V(O)
Atome binaire d’informations : le bit
(binary digit – chiffre binaire)
valeur booléenne (vrai ou faux)
Deux interprétations :
valeur numérique (0 ou 1 (ou ̸= 0))
Numération binaire (compter avec 2 chiffres)
0 1 2 3 4 5 6 7
O I IO II IOO IOI IIO III
8 9 10 11 12 13 14 15
IOOO IOOI IOIO IOII IIOO IIOI IIIO IIII
Information binaire
Tableau comprenant la représentation de plusieurs nombres selon le
type char (sur un octet).
Crédits : [Link]
notions-avancees/la-representation-des-types/
Calcul binaire
Calculs sur les chiffres :
▶ booléen : I and I = I
▶ arithmétique : I + I = IO
Calculs sur les suites de chiffres (nombres) :
▶ booléen : IOIO and OOII = OOIO
▶ arithmétique : IOIO + OOII = IIOI
On sait réaliser ces calculs par circuits électroniques
Mémoire binaire
On sait aussi réaliser la mémorisation par circuits électroniques
Organisation de la mémoire
▶ octet : paquet de 8 bits
OOIOIOIO
▶ mot mémoire : paquets de 4 ou 8 1 octets
OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO
▶ séquence de mots mémoire
OOOOOOOO OOOOOOOO OOOOOOOO OOIOIOIO
OOIIOIOO OOIIOOIO OOOOOOOO OOOOOOOO
OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO
OOIOIOIO OOIOIOIO OOIOIOIO OOOOOOOO
...
1. architecture 32 bits ou 64 bits
Structure et accès mémoire
Structure séquentielle contigüe ⇒ structure indicée
Position en mémoire = adresse mémoire
0 OOOOOOOO OOOOOOOO OOOOOOOO OOIOIOIO
4 OOIIOIOO OOIIOOIO OOOOOOOO OOOOOOOO
8 OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO
12 OOIOIOIO OOIOIOIO OOIOIOIO OOOOOOOO
.. ..
. .
Unité d’adressage : octet
Chaque valeur manipulée par programme possède une adresse
mémoire
Données, types et mémoire
En mémoire : toutes les valeurs sont numériques
codées en binaire
Données et types de base
Type Taille 2
Nombres entiers / Caractères char 1
Nombres entiers short 2
int 4
long 8
Nombres à virgule float 4
double 8
2. en octets, machine dependent
Types et données en mémoire
C’est le programme et donc, le programmeur qui décide de
l’usage des valeurs en mémoire.
OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO char ’*’ (caractère étoile)
OOOOOOOO OOIOIOIO OOIOIOIO OOIOIOIO short 42
OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO short 10794
OOOOOOOO OOOOOOOO OOOOOOOO OOIOIOIO int 42
OOIOIOIO OOIOIOIO OOIOIOIO OOIOIOIO int 707406378
Types et données en mémoire
Et les float ?
Interprétation en 3 parties : signe, mantisse, exposant.
Crédits : [Link]
notions-avancees/la-representation-des-types/
Types et données en mémoire
Et les float ?
Interprétation en 3 parties : signe, mantisse, exposant.
Crédits : [Link]
notions-avancees/la-representation-des-types/
Types et données en mémoire
Attention :
Les octets OOOOOOOO OOOOOOOO OOOOOOOO OOIOIOIO
n’ont pas le même sens suivant qu’ils sont de type int ou
float .
Démo : float int.c
Et les programmes ?
Si on ouvre un fichier exécutable avec un éditeur de texte :
<CF><FA><ED><FE>^G^@^@^A^C^@^@^@^B^@^@^@^P^@^@^@
X^E^@^@<85>^@ ^@^@^@^@^@^Y^@^@^@H^@^@^@__PAGEZERO
^@^@^@^@^@^@^@^@^@^@^@
...
ou mieux, avec un éditeur hexadécimal
01ebe814063727473747566662e6305f5f43544f525f4c
5f05f5f44544f525f4c4953545f5f05f5f4a43525f4c49
53545f5f05f5f646f5f676c6f62616c5f64746f72735f6
75780636f6d706c657465642e36353331064746f725f69
...
Et les programmes ?
01ebe814063727473747566662e6305f5f43544f52
5f05f5f44544f525f4c4953545f5f05f5f4a43525f
53545f5f05f5f646f5f676c6f62616c5f64746f727
75780636f6d706c657465642e36353331064746f72
...
Chaque octet a une adresse
0x7ffee345b300 11110011010100011101100101010101
0x7ffee345b304 11010001010100011100110101011101
0x7ffee345b308 11010001010100011101100101010101
0x7ffee345b30c 11010001010100011101100111010101
0x7ffee345b310 10010001010100011101100101010001
0x7ffee345b314 11010001010100011101101101010111
Organisation de la mémoire
Les programmes et les données
Paramètres,
Pile Variable locales
sp
Stack pointer
Mémoire non allouée
Tas Données dynamiques
gp Données Variables globale
Global pointer
Code Instructions du programme
pc
Program count
Crédits :
[Link]
Variables : déclarations et adresses
Trois catégories de ≪variables≫
1 #i n c l u d e < s t d i o . h>
2
3 i n t n = 4 1 ; // g l o b a l e
▶ globales au programme 4 i n t f ( i n t x ) { // param è t r e
5 r e t u r n x +1:
▶ locales à une fonction 6 }
7 i n t main ( ) {
▶ paramètres de fonctions 8 i n t x = f ( n ) ; // l o c a l e
9 p r i n t f ( ”%d” , x ) ;
10 }
Localisations :
▶ globales : dans la zone des données
▶ locales et paramètres : dans la zone de la pile
Nous verrons plus tard l’utilisation du tas
La pile : variable, portée
Exemple : que fait ce code (Ex bloc1.c) ?
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ;
10 p r i n t f ( ”%d\n” , x ) ; // ( 3 )
11 return 0;
12 }
[Link]
Dynamique de la pile
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ;
10 p r i n t f ( ”%d\n” , x ) ; // ( 3 )
11 return 0;
12 } main x 0
pile (1)
Dynamique de la pile
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ; fonction f x 41
10 p r i n t f ( ”%d\n” , x ) ; // ( 3 )
11 return 0;
12 } main 0
pile (2)
Dynamique de la pile
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ;
10 p r i n t f ( ”%d\n” , x ) ; // ( 3 )
11 return 0;
12 } main x 42
pile (3)
La pile : variable, portée
Variables déclarées dans un bloc ne sont valables que
dans ce bloc 3 .
Elles sont :
1. empilées à l’entrée du bloc
2. dépilées en sortie de bloc
Exemple : que se passe-t-il avec ce code (Ex bloc2.c) ?
4 int f ( int x) {
5 i f ( x == 0 ) { [Link]
6 int y = 0;
7 } else {
8 y = 1;
9 }
10 return y ;
11 }
12 i n t main ( ) {
13 i n t a=f ( 4 ) ;
14 p r i n t f ( ”%d\n” , a ) ;
15 return 0;
16 }
3. Un bloc est un suite d’instruction(s) entre une accolade ouvrante et une
fermante, comme le corps d’une fonction ou d’une boucle...
La pile : variable, portée
Variables déclarées dans un bloc ne sont valables que
dans ce bloc 3 .
Elles sont :
1. empilées à l’entrée du bloc
2. dépilées en sortie de bloc
Exemple : que se passe-t-il avec ce code (Ex bloc2.c) ?
4 int f ( int x) {
5 i f ( x == 0 ) { [Link]
6 int y = 0;
7 } else {
8 y = 1;
9 }
10 return y ;
11 }
12 i n t main ( ) {
13 i n t a=f ( 4 ) ;
14 p r i n t f ( ”%d\n” , a ) ;
15 return 0;
16 }
3. Un bloc est un suite d’instruction(s) entre une accolade ouvrante et une
fermante, comme le corps d’une fonction ou d’une boucle...
La pile : variable, portée
Et celui ci (Ex bloc3.c) ?
[Link]
4 int f ( int x) {
5 i f ( x == 0 ) {
6 int y = 0;
7 } else {
8 int y = 1;
9 }
10 return y ;
11 }
12 i n t main ( ) {
13 i n t a=f ( 4 ) ;
14 p r i n t f ( ”%d\n” , a ) ;
15 return 0;
16 }
La pile : variable, portée
Et celui ci (Ex bloc3.c) ?
[Link]
4 int f ( int x) {
5 i f ( x == 0 ) {
6 int y = 0;
7 } else {
8 int y = 1;
9 }
10 return y ;
11 }
12 i n t main ( ) {
13 i n t a=f ( 4 ) ;
14 p r i n t f ( ”%d\n” , a ) ;
15 return 0;
16 }
La pile : variable, portée
Et celui là (Ex bloc4.c) ?
4 int f ( int x) { [Link]
5 i n t y =22;
6 i f ( x == 0 ) {
7 int y = 0;
8 } else {
9 int y = 1;
10 }
11 return y ;
12 }
13 i n t main ( ) {
14 i n t a=f ( 4 ) ;
15 p r i n t f ( ”%d\n” , a ) ;
16 return 0;
17 }
La pile : variable, portée
Et celui là (Ex bloc4.c) ?
4 int f ( int x) { [Link]
5 i n t y =22;
6 i f ( x == 0 ) {
7 int y = 0;
8 } else {
9 int y = 1;
10 }
11 return y ;
12 }
13 i n t main ( ) {
14 i n t a=f ( 4 ) ;
15 p r i n t f ( ”%d\n” , a ) ;
16 return 0;
17 }
La pile : variable, portée
Code correct => Il est sage de déclarer toutes les variables en
début de fonction
1 int f ( int x) {
2 int y ;
3 i f ( x == 0 ) {
4 y = 0;
5 } else {
6 y = 1;
7 }
8 return y ;
9 }
10 i n t main ( ) {
11 i n t a=f ( 4 ) ;
12 p r i n t f ( ”%d\n” , a ) ;
13 return 0;
14 }
Variable : adresse et valeur
Les deux aspects fondamentaux des variables
▶ une valeur en mémoire
▶ une adresse en mémoire
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ; (0x7ffee345b307)
(0x7ffee345b306)
10 p r i n t f ( ”%d\n” , x ) ; // (0x7ffee345b305)
(3) 0x7ffee345b304
11 return 0; main x 0
12 }
pile (1)
Variable : adresse et valeur
Les deux aspects fondamentaux des variables
▶ une valeur en mémoire
▶ une adresse en mémoire
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ; fonction f x 41 0x7ffee345b308
10 p r i n t f ( ”%d\n” , x ) ; //
(3)
11 return 0; main 0 0x7ffee345b304
12 }
pile (2)
Variable : adresse et valeur
Les deux aspects fondamentaux des variables
▶ une valeur en mémoire
▶ une adresse en mémoire
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 int f ( int x) {
5 r e t u r n x +1; // ( 2 )
6 }
7 i n t main ( ) {
8 i n t x =0; // ( 1 )
9 x=f ( 4 1 ) ;
10 p r i n t f ( ”%d\n” , x ) ; //
(3)
11 return 0; main x 42 0x7ffee345b304
12 }
pile (3)
Variable et adresse en C
Il est possible de manipuler les adresses des variables en C
Une variable peut contenir une adresse
Une variable qui contient une adresse est appelée pointeur (vers
une certaine valeur)
Pour déclarer un pointeur, on utilise *.
Exemple : int ∗n;
La variable n contiendra l’adresse d’une variable de type int
Nous utiliserons aussi char ∗ et float ∗.
On peut obtenir l’adresse d’une variable avec l’opérateur &
Exemple
1 #i n c l u d e <s t d i o . h>
2 #i n c l u d e <s t d l i b . h>
3
4 i n t main ( ) {
5 int x = 0 ;
6 i n t ∗p ;
7 p=&x ;
8 p r i n t f ( ”%d %p\n” , x , p ) ;
9 return 0;
p 0x7ffee345b304 0x7ffee345b308
10 }
main x 0 0x7ffee345b304
pile
Variable : adresse et valeur (bis)
Déréférencement : pour obtenir la valeur pointée par a on
utilise l’opérateur * : *p donne l’entier 0.
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 i n t main ( ) {
5 int x = 0 ;
6 i n t ∗p ;
7 p=&x ;
8 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
9 return 0;
10 }
Variable : adresse et valeur (bis)
Partage et effet de bord : en modifiant x, on modifie (aussi) la
valeur pointée par p : après x = x+1, *p vaut 1
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 i n t main ( ) {
5 int x = 0 ;
6 i n t ∗p ;
7 p=&x ;
8 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
9 x=x +1;
10 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
11 return 0;
12 }
Variable : adresse et valeur (bis)
On peut aussi écrire :
1 #i n c l u d e < s t d i o . h>
2 #i n c l u d e < s t d l i b . h>
3
4 i n t main ( ) {
5 int x = 0 ;
6 i n t ∗p ;
7 p=&x ;
8 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
9 ∗p=∗p +1; // x=x +1;
10 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
11 return 0;
12 }
Le résultat est le même : x contient la valeur 1.
Variable : adresse et valeur (bis)
1 i n t main ( ) {
2 int x = 0 ;
3 i n t ∗p ;
4 p=&x ;
5 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
6 ∗p=∗p +1; // x=x +1;
7 p r i n t f ( ”%d %p %d\n” , x , p , ∗p ) ;
8 return 0;
9 }
Affectation : x = x+1
▶ le x à gauche désigne l’adresse
▶ le x à droite désigne la valeur à cette adresse
Affectation avec un pointeur : *p = *p+1
▶ le *p à gauche désigne l’adresse contenue dans a (ici, adresse
de a)
▶ le *p à droite désigne l’entier contenu à l’adresse contenue
dans p (ici, la valeur de x)
⇒ ≪ effet de bord ≫ : après *p = *p + 1, x vaut 1
Pointeurs dans les paramètres de fonction
Les paramètres d’une fonction peuvent être des pointeurs :
int f ( float ∗p);
Pointeurs dans les paramètres de fonction
Inverser les valeurs de deux variables entières x et y :
1 int t , x =1 , y =2;
2 t = x;
3 x = y;
4 y = t;
Fonction d’échange
1 void swap ( int x , int y ) {
2 int t ;
3 t = x;
4 x = y;
5 y = t;
6 }
Ne fonctionne pas (dessiner la pile au tableau)
Pointeur, valeur, affectation
Pour que cela fonctionne : passer en paramètres des adresses ;
1 void swap ( int *x , int * y ) {
2 int t ;
3 t = *x;
4 *x = *y;
5 *y = t;
6 }
7
8 int main () {
9 int a =2 , b =3;
10 printf ( " a : % d b : % d \ n " , a , b ) ;
11 swap (& a , & b ) ;
12 printf ( " a : % d b : % d \ n " , a , b ) ;
13 return 0;
14 }
(dessiner la pile au tableau)
C’est tout pour aujourd’hui !