Vous êtes sur la page 1sur 43

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 : https://zestedesavoir.com/tutoriels/755/le-langage-c-1/
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 : https://zestedesavoir.com/tutoriels/755/le-langage-c-1/
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 : https://zestedesavoir.com/tutoriels/755/le-langage-c-1/
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 :
http://pageperso.lif.univ-mrs.fr/~alexis.nasr/Ens/Compilation/mips.pdf
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 }

https://app.wooclap.com/OIJNQR
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 ) { https://app.wooclap.com/OIJNQR
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 ) { https://app.wooclap.com/OIJNQR
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) ?


https://app.wooclap.com/OIJNQR
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) ?


https://app.wooclap.com/OIJNQR
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) { https://app.wooclap.com/OIJNQR
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) { https://app.wooclap.com/OIJNQR
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 !

Vous aimerez peut-être aussi