Introduction

publicité
C1 : INTRODUCTION
Sommaire :
1 Préliminaire :
- Se positionner dans l’ordinateur
2 Programmation : rapide tour d’horizon :
- Compilateur
- Variables, fonctions
- Environnement de développement
- Fonction « main »
3 Qu’est ce qu’une variable ? Plongée en mémoire :
- Mémoire adresse
- Adresse, « mots »
- « Nombre-octets » (notation étendue, troncature)
- Codage des nombres négatifs (à titre indicatif)
- Des « types » de variables
- Variables par unité ou par ensembles.
- Se représenter les variables dans la mémoire
Références bibliographiques
1
2
Introduction :
Nous situer dans l’ordinateur et ses différents niveaux d’intervention.
L’ordinateur : une hiérarchie d’abstractions, des niveaux ou encore machines virtuelles
NIVEAU - ABSTRACTION
6
Programmes applicatifs
5
Langage de programmation
4
Langage assembleur
3
Noyau du système d’exploitation
2
Langage machine
1
Microprogramme
0
Logique numérique
<-Nous sommes ici
0 : Logique numérique, circuits électroniques de l’ordinateur, portes logiques (ET, OU)
univers binaire 0/1
1 : Microprogramme, premier niveau de langage, tous les ordinateurs ne le possèdent pas
(des séquences d’étapes utilisées par le niveau 2 du langage machine)
2 : Langage machine : à ce niveau, ajouter 2 nombres, déplacer des données d’un
emplacement vers un autre, déterminer si un nombre est égal à 0 sont des instructions
élémentaires suffisantes pour exécuter n’importe quel programme ou application des niveaux
plus élevés !
3 : Noyau système exploitation : ordonnancer et allouer les ressources d’un ordinateur aux
différents programmes s’exécutant sur la machine. Il peut être programmé dans un langage de
programmation de haut niveau qui a été traduit en langage machine, c'est-à-dire compilé.
Rappelons que Le langge C a été créé initialement pour écrire le système d’exploitation
UNIX.
En plus du noyau le système d’exploitation complet comprend des programmes applicatifs
(niveau 6), le plus souvent un rôle d’interface (gestion des fichiers, gestion des fenêtres etc.)
4 : Le langage d’assemblage est une représentation symbolique des instructions rencontrées
aux niveaux inférieurs. Un programme en langage d’assemblage est converti en instructions
de niveau inférieur par un traducteur appelé un assembleur
5 : Les langages de hauts niveaux grâce auxquels les applications peuvent être écrites plus
facilement qu’en langage assembleur. Il existe des milliers de langages à ce niveau (les plus
connus, Basic, C, pascal, Cobol, Fortan, Lisp…)
Ils font eux-mêmes l’objet d’une classification en strates C, C++, JAVA, JAVASCRIPT…
par exemple)
6 : Les applications ou collections de programmes dans des domaines multiples et variés.
3
1 Compilateur, variables, fonctions, environnement, fonction « main »
Compilateur
Le compilateur est un programme qui lit un programme écrit dans un premier langage _ le
langage source _ et le traduit dans un programme équivalent écrit dans un autre langage _ le
langage cible _ Eventuellement il peut signaler des erreurs dans le programme source. Si l’on
écrit un programme en C, le langage C est le source et lorsque l’on fabrique un exécutable, la
compilation réalise sa traduction en langage machine.
En général le compilateur est accompagné d’une interface de type traitement de texte qui
permet l’écriture des programmes en langages source.
Variables, fonctions
Au niveau le plus basique de l’écriture de programmes on a des variables et des fonctions.
Ecrire un programme c’est définir des variables et concevoir des fonctions qui correspondent
aux traitements opérés sur les variables.
Les fonctions sont simplement des ensembles d’instructions qui modifie les valeurs des
variables, selon les traitements que l’on souhaite opérer sur ces variables, les données. La
notion d’algorithme correspond à la construction des fonctions ainsi qu’à l’organisation des
fonctions entre elles. Un algorithme est une suite finie d’instructions en vue de
l’accomplissement d’une tâche.
Environnement
Il est impossible aux programmeurs de réinventer la roue à chaque nouveau projet ! En
général tout projet s’appuie sur un environnement qui offre, outre le compilateur, des
librairies de fonctions prêtes à l’emploi.
Librairies standards
Le langage C est accompagné d’un certain nombre de librairies dites « standards ». Elles
comprennent des fonctions de base dans différents domaines. Par exemple <math.h>,
<string.h>, <stdlib.h>, <stdio.h>, <time.h>, etc.
printf(), scanf(), rand()
Dans les exemples qui suivent, nous utiliserons les fonctions de la librairie <stdio.h> printf()
et scanf() et de la librairie <stdlib.h> la fonction rand(). Nous détaillerons plus tard ces
fonctions, principalement :
- La fonction printf() permet d‘afficher une chaîne de caractères dans une fenêtre console.
Elle utilise un fichier nommé stdout qui est automatiquement et invisiblement créé au
lancement du programme.
- La fonction scanf() permet de récupérer des entrée clavier
Elle utilise un fichier stdin qui est créé en même temps que stdout.
- La fonction rand() renvoie une valeur comprise entre 0 et RAND_MAX.
D’autres librairies libres de droits ou pas dans tous les domaines
D’autres librairies dans des domaines spécialisées peuvent être ajoutées et utilisées, par
exemple la très bonne librairie « allegro » (A Low Level Game Routine) pour la création de
jeux vidéos.
4
Fonction main()
Pour le système d’exploitation, un exécutable se traduit par une pile d’instruction avec une
entrée, en quelque sorte la « tête » du programme, pour le programmeur c’est la fonction
main(). Ainsi tout programme commence par un main().
Selon le système d’exploitation ou l’environnement de développement, le main() peut avoir
des caractéristiques spécifiques. Mais le main() standard a l’aspect suivant :
Exemple de programme qui affiche dans une fenêtre console « bonjour » :
int main()
// tête ou entrée du programme,
{
// ouverture bloc d’instructions
// appel de la fonction printf() qui affiche la chaîne de caractères passée
// en paramètre
printf(« bonjour ») ;
// arrêter le programme pour avoir le temps de lire le résultat
system(« PAUSE ») ;
// valeur de retour de la fonction qui indique un bon déroulement.
return 0 ;
}
// fermeture bloc d’instructions
Le signe // dans un programme indique que tout ce qui suit n’est plus considéré comme du
code opérationnel mais est un commentaire sur le code ou du code mis en commentaire.
2 Plongée en mémoire : adresse, « mots », nombre-octets, variables et types
Mémoire, adresse, mots
Selon les explications données par Alfred Aho et Jeffrey Ullman, la mémoire repose sur des
« puces mémoires » ou « puces RAM ». Une puce est un circuit intégré, d’environ un
centimètre carré qui rassemble un grand nombre de conducteurs et composants électriques.
C’est là où sont casés les fameux « bits » en grande quantité. Leur nombre est toujours une
puissance paire de deux ; c’est-à-dire 22i avec i un entier. Tous les bits ont une adresse et ils
sont en quelque sorte alignés du premier, d’adresse « 0 », au dernier dont l’adresse correspond
au nombre de bits sur la puce. Du fait de cette adresse il est possible de lire et d’écrire sur
chaque bit de la puce mémoire [AHO, 1993, p. 171].
Mais la mémoire principale est construite avec pour unité de base l’octet : c’est la plus petite
quantité de stockage. Pour avoir des octets, huit puces sont placées en parallèle. Huit puces
sont alignées sur la même adresse. Chaque puce fournit alors un bit de l’octet et ils sont lus ou
écrits en même temps. Lire un octet prend alors le même temps que de lire un bit.
Ainsi La mémoire d’un ordinateur est une série d’emplacement numérotés contenant chacun
un nombre. Le numéro d’un emplacement est appelé une adresse, un emplacement est un
ensemble de 8 bits.
Le microprocesseur pourra effectuer 2 opérations sur les octets de la mémoire :
1) Modifier le contenu d’un emplacement, la valeur précédente sera écrasée par cette
opération
5
2) consulter le contenu d’un emplacement, cette opération n’altère pas la valeur courante de
l’emplacement [MERCIER, 1989, p 25].
Remarque :
Le micro processeur, cœur de l’ordinateur exécute un nombre limité d’instructions simples :
- déplacer des données en mémoire - inversion de bits (NOT) - opérations logiques (ET, OU)
- addition de bits - déplacement et rotation de bits [MERCIER, 1989, p. 28].
Adresse, mots
Vient ensuite la nécessité de lire et d’écrire un « mot », c’est-à-dire de disposer de plusieurs
octets consécutifs qui conservent possible l’accès à chacun d’entre eux. Le plus souvent la
mémoire est construite sur la base de quatre octets consécutifs ; 32 bits qui ne remettent pas
en cause la définition de l’octet comme plus petite unité de mémoire ayant sa propre adresse.
Pour ce faire deux niveaux d’adresses sont dégagés. Celui du mot, de quatre octets en quatre
octets, et celui, interne au mot, des octets qui le constitue. Si « a » est l’adresse d’un mot,
« a+0 », « a+1 », « a+2 », « a+3 » sont les adresses de ses octets ; et « a » progresse de quatre
en quatre, a est toujours divisible par quatre. Ce principe permet de conserver l’octet comme
plus petite unité de stockage mais également, en 32 bits avec 32 puces parallèles, de
bénéficier d’un quasi parallélisme sur quatre octets [AHO, 1993, p. 172].
Nombre octets (notation étendue – binaire – décimal -tronquature),
La mémoire de l’ordinateur correspond à une réalité physique corrélée avec une réalité
Idéelle humaine qui touche aux mathématiques : le nombre. Ce concept n’existe pas dans la
nature. C'est-à-dire qu’au niveau même de la simple variable on a cette dualité entre réalité
physique de l’ordinateur et imaginaire humain. Comment se relient la réalité physique de
l’ordinateur et le concept humain de nombre ?
Notation étendue
Rappelons qu’un nombre décimal comme « 8542 » peut s’écrire de la façon suivante
[LIPSCHUTZ, 1983, p. 2 à 5] :
8542 = 8*103 + 5*102 + 4*101 + 2*100
= 8*1000 + 5*100 + 4*10 + 2*1
= 8000 + 500 + 40 + 2 .
Et cette décomposition constitue ce qui est
nommée la notation étendue de l’entier
De même un nombre binaire peut-être représenté en notation étendue. Si l’on prend par
exemple le chiffre binaire 110101 on obtient :
110101 = 1*25 + 1*24 + 0*23 + 1*22 + 0*21 + 1*20
et il n’y a plus qu’à effectuer le calcul :
110101 = 32 + 16 + 0 + 4 + 0 + 1
= 53
De l’octet binaire aux nombres décimaux
Les bits sont disposés de droite à gauche de la position 0 à la position 7 comprises. La
puissance correspond à la position du bit (« pos » sur la figure 9.2) et la valeur à additionner
résulte de la multiplication de 2pos par la valeur du bit.
Le nombre 110101 de l’exemple ci-dessus donne l’octet suivant :
6
bit 8 bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1
pos 7 pos 6 pos 5 pos 4 pos 3 pos 2 pos 1 pos 0
27
26
25
24
23
22
21
20
0
0
1
1
0
1
0
1
0
+32
+0
+16
+0
+4
+0
+1
On constate que le nombre décimal le plus grand codé sur un octet est 255. Ce serait :
27 + 26 + 25 + 24 + 23 + 22 + 21 + 20 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255
Et comme la valeur zéro compte pour un nombre, sur un octet on a 256 nombres possibles,
soit 28 cas. Le principe de cette addition est le même pour 16 bits avec des positions de 0 à
15 et avec cette fois 216 cas. Idem pour 24 bits avec 224 cas et 32 bits avec 232 cas. En fait pour
n bits il y a n positions de 0 à n -1 ce qui donne un total de 2n cas.
Dépassement de capacité
Si le nombre à coder dépasse la possibilité de codage qu’offre l’espace mémoire, il y a un
dépassement de capacité.
Par exemple un seul octet ne peut pas restituer des nombres supérieurs à 255. Pour ces
nombres il se comporte comme si un modulo 28 était effectué, et la partie qui dépasse est
tronquée. Affecter la valeur 257 à un octet donne 257 modulo 256 ce qui est égal à 1 :
257
1
0
0
0
0
0
0
0
1
1
Codage des nombre négatifs (quelques précisions à titre indicatif)
Entier signé ou non-signé
Dans le langage C, tout nombre est implicitement dit « signé » ce qui veut dire qu’il peut
prendre des valeurs négatives ou positives. Cette propriété est attribuée par défaut à tous les
types d’entiers. Mais il est possible d’avoir des nombres « non signés » qui excluent la
propriété d’être positif ou négatif et dont la grandeur sera calculée sans système de signe. Le
mot clé utilisé pour définir un entier « non signé », est « unsigned ».
L’éventualité pour un nombre entier d’être négatif nécessite le codage de cette propriété du
nombre avec le nombre lui-même. Prenons par exemple un nombre codé sur un octet, c’est le
type « char » que nous présentons plus loin. Pour qu’il soit signé on peut par exemple utiliser
la dernière position, le huitième bit, comme bit de signe avec 0 pour positif et 1 pour négatif.
Tous les autres bits sont alors réservés à la grandeur que peut prendre ce nombre. Dans ce cas
on obtient pour un octet des valeurs de 127 à –127. Mais il y a plusieurs problèmes. D’abord
il y aura deux 0, un positif et un négatif. Et aussi les opérations d’addition ou de soustraction
entre nombres positifs et négatifs seront compliquées. Si x et y ont des signes différents le
7
signe de x+y est celui du plus grand en valeur absolue. Il faut donc commencer par connaître
lequel des deux est le plus grand pour connaître le signe du résultat, puis soustraire du plus
grand le plus petit.
Il y a plusieurs méthodes possibles pour le codage des nombres négatifs. Nous allons évoquer
la méthode du complément à deux. Cette méthode a l’avantage de permettre la transformation
d’une soustraction en addition. Rappelons que parmi le nombre limité d’instructions simples
que le microprocesseur effectue, il y a l’addition de bits. C’est une solution rapide.
Principe du complément en binaire
Le complément à 2 d’un nombre binaire c’est son inverse +1, par exemple :
Nombre binaire
inverse
Complément à 2
11010011
00101100
00101101
11001100
00110011
00110100
Complément à deux dans un système de signes
La notation en complément à deux départage les nombres positifs des nombres négatifs selon
la valeur du bit de tête (le plus à gauche).
S’il est égal à 0 le nombre est positif. Son interprétation est faite comme s’il s’agissait d’une
grandeur non signée. Pour n bits, il sera compris dans la fourchette 2n – 1 – 1 à 0. Sur un octet
les valeurs possibles seront comprises entre 127 et 0, c’est-à-dire de 27 – 1 à 0.
En revanche si le bit de tête est égal à 1, il est interprété comme un nombre négatif. Puisque le
bit de tête est égal à 1, les grandeurs s’échelonnent entre 2n – 1 et 2n – 1, c’est-à-dire pour un
octet entre 128 et 255. Ces valeurs sont interprétées comme étant celles des compléments à
deux des valeurs positives et, pour n bits, par rapport à 2n. Pour obtenir les valeurs négatives
qu’elles désignent il suffit de soustraire 2n du complément à deux ce qui donne :
CA – 2n = – A
Exemple avec une taille des nombres limités à 4 octets
Par exemple prenons n = 4. Nous pouvons visualiser la situation avec un tableau qui
récapitule ce principe de codage du signe (figure 1) :
Pour n = 4, il y a 16 nombres possibles qui vont de 0 à 15. Les nombres positifs vont de 0 à 7.
0 n’a pas de correspondant négatif car le complément à deux de 0 est 2 4 ramené à 0 par le
modulo 24. Les nombres dont les valeurs littérales vont de 8 à 15 commencent par 1 et sont
considérés comme négatifs. Ils sont interprétés comme des compléments à deux auxquels est
soustrait chaque fois 24. On utilise le principe de la notation étendue et de l’addition des
puissances de deux et l’on soustrait 24 ce qui produit la valeur négative correspondante.
Notons que le complément à deux de cette valeur négative revient à la valeur positive (Le
complément à deux du complément à deux donne la valeur de départ). Les deux nombres,
positif et négatif, sont reliés par cette relation de complémentarité à deux. Si l’on additionne
par exemple 7 et – 7 ça fait 0111 + 1001 = 10000, la retenue provenant du bit de tête, 24, est
éliminée ce qui donne 0.
8
NOMBRES
POSITIFS
Valeur
Valeur binaire Complément
décimale correspondante
à deux
« CA »
0
0000
1
0001
1111
2
0010
1110
3
0011
1101
4
0100
1100
5
0101
1011
6
0110
1010
7
0111
1001
1000
Valeur
décimale
littérale
15
14
13
12
11
10
9
8
NOMBRES
NEGATIFS
Interprétation en nombre négatif
du complément à deux avec la méthode :
CA – 2n
–1
–2
–3
–4
–5
–6
–7
–8
= 1*23 + 1*22 + 1*21 + 1*20
= 1*23 + 1*22 + 1*21
= 1*23 + 1*22 + 1*20
= 1*23 + 1*22
= 1*23 + 1*21 + 1*20
= 1*23 + 1*21
= 1*23 + 1*20
= 1*23
– 24
– 24
– 24
– 24
– 24
– 24
– 24
– 24
Fig. 1 : Système de signe, méthode du complément à deux.
( Pour mémoire rappelons que 20 = 1, 21 = 2, 22 = 4, 23 = 8, 24 = 16 )
Dépassement de capacité
Le problème du dépassement de capacité peut se poser. L’addition de deux entiers positifs,
pour être juste ne doit pas être supérieure à la valeur positive maximum qui peut être codée
dans le système signé. Par exemple 7+7 = 14 en grandeur absolue soit 1110 en binaire. Dans
notre système signé et sur 4 bits ça donne le nombre – 2.
De même pour l’addition de nombres négatifs. -7 + - 7 = 1001 + 1001 = 10010 soit 0010
après suppression de la retenue c.à.d le nombre 2.
En revanche le résultat est juste quelles que soient les opérations s’il reste dans les limites
définies par le nombre n de bits du codage ( de 0 à 7 et de -1 à -8 dans notre exemple sur
quatre bits) : -3+-4 = 1101 + 1100 =11001 soit 1001 après suppression de la retenue c.à.d le
nombre -7 qui est le juste résultat.
Nous constatons également que la soustraction est opérable par une addition, ce qui est une
propriété des compléments à deux. Est additionné un nombre interprété négatif :
3 – 7 = 0011 + 1001 = 1100 ce qui représente le résultat – 4 .
Types (char, short, int, long, float, double, pointeur)
Le nombre de bits qui servent au codage des nombres définit la fourchette des valeurs
possibles que pourront prendre ces nombres. Chacun des types correspond à une taille en
octets :
1. « char » pour caractère, codé sur un octet, s’il est signé sa valeur va de -27 à 27 -1, soit
de -128 à +127. S’il n’est pas signé sa valeur est comprise entre 0 et 28 -1, soit 255.
2. « short int » pour entier court codé sur deux octets est généralement abrégé en
« short » . S’il est signé sa valeur va de -215 à 215 -1 c’est-à-dire de –32768 à 32767.
S’il n’est pas signé sa valeur est comprise entre 0 et 216 -1, soit 65535.
3. « long int » pour entier long, codé sur quatre octets est abrégé en « long ». S’il est
signé sa valeur va de -231 à 231-1 c’est-à-dire de –2147483648 à 2147483647. S’il
n’est pas signé il prend des valeurs entre 0 et 232 –1, soit 4294967295.
9
4. En fonction de l’environnement de programmation, le « int » tout court est soit
analogue au short soit analogue au long : « chaque compilateur est libre de choisir des
tailles d’entiers adaptés à la machine sur laquelle il tourne, mais il doit respecter des
tailles minimales de 16 bits pour les types short et int, et de 32 bits pour le type long.
De plus les shorts ne doivent pas être plus longs que les ints, qui ne doivent pas être
plus longs que les longs. » [KERNIGHAN, 1995, p. 36]. Dans l’environnement sur
lequel nous travaillons, PC-Windows et compilateur Visual C++ 6, le « int » est sur
quatre octets, analogue au long.
5. float et double correspondent aux nombres à virgule.
Notons que par défaut ils sont signés (c'est-à-dire qu’ils acceptent des valeurs positives et
négatives) sinon ils sont préfixés par le mot-clé « unsigned ».
6. le pointeur est un type particulier de variable : une variable qui peut contenir une
adresse mémoire ( en général un nombre hexadécimal) et rien d’autre. C’est une
variable dont le rôle est de permette d’accéder à des adresses mémoire.
Variables par unité ou par ensembles :
Les variables peuvent être appréhendées par unités ou par ensemble selon deux optiques :
- le Tableau est un ensemble d’objets de même type.
Par exemple un tableau de 10 chars se déclare de la façon suivante dans un programme :
char tab[10] ;
// 1*10=10 octets
un tableau de 34 entiers :
int toto[10] ;
//4*10= 40 octets
Un tableau de 12 pointeurs :
Char* str[15] ;
// 4*15= 60 octets
Taille de tableaux
En C la taille du tableau doit être explicite, taille de l’objet*taille du tableau donne la taille
totale réservée en mémoire.
Accès aux éléments d’un tableau
L’accès aux différents éléments se fait avec l’opérateur crochet [ ] et tous les éléments sont
indicés de 0 à Taille du tableau :
toto[0] toto[1] toto[2] toto[3] toto[4] ... toto[9] // éléments numérotés de 0 compris à 9
compris
- la structure est un ensemble d’objets de types différents
Par exemple une structure pour stocker les caractéristiques d’un personnage pourra être
déclarée comme suit dans un programme :
struct ennemi{
char* name;
// nom de l’ennemi
char injure[80] ;
// injure potentielle
int x,y ;
// la position à l’écran
int pasx, pasy ;
// la vitesse du déplacement
int style ;
// style d’ennemi
10
int dtmps ;
int maxt ;
int tmps ;
// heure entrée
// temps maximum d’apparition
// temps courant
// etc.
};
Taille d’une structure
La structure a une taille fixe. La taille d’une structure en mémoire est légèrement supérieure à
la somme des tailles de ses éléments à cause de l’alignement des adresses mémoire (voir « Se
représenter les variables en mémoire » plus bas).
Accès aux éléments d’une structure
L’accès aux différents champs de la structure se fait avec l’opérateur . (point).
Soit une structure dans le programme :
struct ennemi ee ;
ee.name= « arthur » ;
strcpy(ee.injure, « gros chnouf ») ;
ee.x=rand()%TX ;
ee.y=rand()%TY ;
// nom de l’ennemi
// vocabulaire de l’ennemi
// position horizontale aléatoire dans l’écran
// position verticale aléatoire dans l’écran
Remarque :
il peut y avoir des tableaux dans une structure et il peut y avoir des tableaux de structures. Par
exemple dans un programme la déclaration :
struct ennemi tab[50] ;
Cette déclaration réserve un bloc de mémoire consécutive de la taille de 50 structures
« ennemi ».
Se représenter les variables dans la mémoire
Lorsque dans le programme des variables de différents types sont déclarées, les octets qui leur
sont nécessaires sont alloués de façon consécutive dans la mémoire principale de l’ordinateur
à partir d’une adresse donnée. Toutefois, à part pour le type char (un octet) les variables ont
besoin de commencer sur une frontière de mot, c’est-à-dire à une adresse divisible par quatre,
ce que nous avons vu un peu plus haut.
Ainsi, soit la déclaration suivante :
struct{
char toto ;
int titi ;
};
Cette structure va probablement demander huit octets et non pas cinq en mémoire du fait d’un
besoin d’alignement de l’entier « titi » sur une frontière de mot. Cette nécessité d’alignement
peut engendrer « des trous » non référencés dans la structure [KERNIGHAN, 1995, p.136].
Admettons maintenant la déclaration suivante :
11
int i, j ;
char tab[6] ;
struct bob{
int titi ;
char toto[5] ;
};
int calc[5] ;
Et prenons arbitrairement 100 comme première adresse pour la variable « i » ; « j » est à 104,
(le type int représente quatre octets ) « tab » commence ainsi à 108 jusque 114 (le char fait un
octet). « bob » commence sur une frontière à 116 donc il n’y a rien de 114 à 116. « bob.titi »
prend quatre octets jusque 120 et « toto » cinq octets, jusque 125. A nouveau rien de 125 à
128 et « calc » commence sur une frontière à 128 jusque 148. Cette situation est illustrée par
la figure ci-dessous.
100
104
108
114
116
116
i
120
j
tab[0]
.
.
.
tab[5]
125
128
148
bob.titi
bob.toto[0] ...
bob.toto[4]
struct bob
calc[0]
.
.
.
calc[4]
Se représenter des variables en mémoire
Références bibliographiques
AHO Alfred, ULLMAN Jeffrey, Concepts fondamentaux de l’informatique, Dunod, Paris
1993.
BRAQUELAIRE Jean-Pierre, Méthodologie de la programmation en C, Masson, Paris 1998.
KERNIGHAN Brian, RITCHIE Dennis, Le langage C, Masson, Paris 1995, première édition
1978.
LIPSCHUTZ Seymour, Mathématiques pour informaticiens, McGraw-Hill International,
Angleterre 1983.
MERCIER Philippe, Assembleur, une découverte pas à pas, Marabout Informatique, Alleur
(Belgique) 1989.
12
Téléchargement