NSY 103 - Notes de cours - desvigne.org

Ce document contient les notes de cours de l'UE du CNAM « NSY103 ..... session. 2/ d'un examen écrit comptant pour ¾ de la note finale. ...... Ce chargeur va ensuite charger le MBR (master boot record), situé dans les ... l1:1:wait:/etc/rc. d/rc 1.

un extrait du document



Méthodes de programmation systèmes
UE n° NSY103


Notes de cours


Code de l’UE :
NSY103

Titre de la formation :
Méthodes de programmation systèmes

Ouvert :
Ouvert

Type de diplôme :
Unité de valeur CNAM.

Nombre d'heures :
55h (~18 + 1 cours de 3 heures)

Durée de la formation :
Un semestre - Période : deuxième semestre

Jours de cours
Lundi & Mercredi

Heures de cours
18h00-21h00

Lieu de la formation :
CUCES UNIVERSITES

Salle :
 S05 LE LUNDI ET S18 LE MERCREDI (à confirmer)

URL :
http://cours.desvigne.org/

Animateur
Emmanuel DESVIGNE






Document sous licence libre FDL - © Emmanuel DESVIGNE, version 1.0b, avril 2008
Avant propos
Ce document contient les notes de cours de l’UE du CNAM « NSY103 : méthodes de programmation systèmes ».
Il a été élaboré à partir des connaissances acquises lors de ma formation initiale (DESS ingénierie des réseaux et systèmes, obtenu à Nancy en 1995), de diverses expériences professionnelles (je travaille actuellement comme responsable informatique à la maternité régionale de Nancy), à l’aide de la mine d’or que représente Internet, et à l’aide de ces quelques livres :
Joëlle Delacroix – Linux : programmation système et réseau, Dunod 2003 ;
Andrew Tanenbaum – Systèmes d’exploitation, Pearsoneducation 2003 ;
Jean-Marie Rifflet – La programmation sous Unix - 3ème édition, Ediscience 1993 ;
Jean-Marie Rifflet – La communication sous Unix - 2ème édition, Ediscience 1994.
Dans ces conditions, difficile de revendiquer la paternité du présent melting pot. Aussi, ce document est mis sous licence libre GNU-FDL. Vous pouvez le copier, l’imprimer, le diffuser, voire l’apprendre librement.
Le programme officiel invite le formateur à ne voir que les systèmes Linux et Linux temps réel. Ces systèmes d’exploitation proposent effectivement tous les mécanismes décrits dans ce document. Ils sont stables, efficaces... Néanmoins, même s’ils ont une certaine préférence des personnes ayant rédigé le programme du CNAM pour des raisons éducatives (et du rédacteur du présent document, avouons-le), il est difficile de faire l’impasse des autres systèmes d’exploitation que le marché propose, comme les Unix, XXX-BSD, Mac OS (qui s’en inspire), et MS-Windows. C’est pourquoi, parfois, les philosophies de ces derniers OS seront indiquées, afin d’illustrer qu’il peut y avoir d’autres solutions/implémentations, et pour que le candidat acquière une culture générale des systèmes d’exploitation.
Ces systèmes d’exploitations sont eux-mêmes très largement écrit en C (et parfois en C++). De plus, les travaux dirigés, travaux pratiques, projets devront être rédigés dans ces langages. Aussi, le premier cours sera en grande partie réservé à une mise à niveau sur ces langages, afin de donner les pointeurs pour que tous les candidats possèdent des bases identiques. Si le volume (en nombre de pages) de cette révision est importante, s’agissant d’un pré-requis, le formateur ne doit pas y passer plus d’une séance. Cette mise à niveau pourra demander une quantité plus ou moins importante de travail personnel de la part des candidats.
Table des matières
 TOC \o "1-3" \h \z  HYPERLINK \l "_Toc196727541" 1 Avant propos  PAGEREF _Toc196727541 \h 2
 HYPERLINK \l "_Toc196727542" 2 Table des matières  PAGEREF _Toc196727542 \h 3
 HYPERLINK \l "_Toc196727543" 3 Programme officiel  PAGEREF _Toc196727543 \h 9
 HYPERLINK \l "_Toc196727544" 3.1 Public concerné et conditions d’accès  PAGEREF _Toc196727544 \h 9
 HYPERLINK \l "_Toc196727545" 3.2 Finalités de l’unité d’enseignement  PAGEREF _Toc196727545 \h 9
 HYPERLINK \l "_Toc196727546" 3.2.1 Objectifs pédagogiques  PAGEREF _Toc196727546 \h 9
 HYPERLINK \l "_Toc196727547" 3.2.2 Capacité et compétences acquises  PAGEREF _Toc196727547 \h 9
 HYPERLINK \l "_Toc196727548" 3.3 Organisation  PAGEREF _Toc196727548 \h 9
 HYPERLINK \l "_Toc196727549" 3.3.1 Description des heures d’enseignements  PAGEREF _Toc196727549 \h 9
 HYPERLINK \l "_Toc196727550" 3.3.2 Modalités de validation  PAGEREF _Toc196727550 \h 9
 HYPERLINK \l "_Toc196727551" 3.4 Contenu de la formation  PAGEREF _Toc196727551 \h 9
 HYPERLINK \l "_Toc196727552" 3.5 Bibliographie  PAGEREF _Toc196727552 \h 10
 HYPERLINK \l "_Toc196727553" 3.6 Contacts  PAGEREF _Toc196727553 \h 11
 HYPERLINK \l "_Toc196727554" 3.6.1 Coordonnées du secrétariat du responsable national :  PAGEREF _Toc196727554 \h 11
 HYPERLINK \l "_Toc196727555" 3.6.2 Coordonnées du responsable de cette formation à NANCY :  PAGEREF _Toc196727555 \h 11
 HYPERLINK \l "_Toc196727556" 3.7 Nouveautés à partir de la session 2006-2007  PAGEREF _Toc196727556 \h 11
 HYPERLINK \l "_Toc196727557" 3.7.1 Origine de la réforme  PAGEREF _Toc196727557 \h 11
 HYPERLINK \l "_Toc196727558" 3.7.2 Résumé du principe de la réforme  PAGEREF _Toc196727558 \h 11
 HYPERLINK \l "_Toc196727559" 3.7.3 Plan imposé par cette réforme pour le cours NSY103  PAGEREF _Toc196727559 \h 12
 HYPERLINK \l "_Toc196727560" 4 Mise à niveau en C/C++  PAGEREF _Toc196727560 \h 13
 HYPERLINK \l "_Toc196727561" 4.1 Bref historique du C  PAGEREF _Toc196727561 \h 13
 HYPERLINK \l "_Toc196727562" 4.2 La compilation  PAGEREF _Toc196727562 \h 13
 HYPERLINK \l "_Toc196727563" 4.3 Les composants élémentaires du C  PAGEREF _Toc196727563 \h 15
 HYPERLINK \l "_Toc196727564" 4.3.1 Les identificateurs  PAGEREF _Toc196727564 \h 15
 HYPERLINK \l "_Toc196727565" 4.3.2 Les mots-clefs  PAGEREF _Toc196727565 \h 15
 HYPERLINK \l "_Toc196727566" 4.3.3 Les commentaires  PAGEREF _Toc196727566 \h 16
 HYPERLINK \l "_Toc196727567" 4.4 Structure d'un programme C  PAGEREF _Toc196727567 \h 16
 HYPERLINK \l "_Toc196727568" 4.5 Les types  PAGEREF _Toc196727568 \h 18
 HYPERLINK \l "_Toc196727569" 4.5.1 Les types prédéfinis  PAGEREF _Toc196727569 \h 18
 HYPERLINK \l "_Toc196727570" 4.5.2 Les types composés  PAGEREF _Toc196727570 \h 19
 HYPERLINK \l "_Toc196727571" 4.6 Les constantes  PAGEREF _Toc196727571 \h 21
 HYPERLINK \l "_Toc196727572" 4.6.1 Les constantes entières  PAGEREF _Toc196727572 \h 21
 HYPERLINK \l "_Toc196727573" 4.6.2 Les constantes réelles  PAGEREF _Toc196727573 \h 22
 HYPERLINK \l "_Toc196727574" 4.6.3 Les constantes caractères  PAGEREF _Toc196727574 \h 22
 HYPERLINK \l "_Toc196727575" 4.7 Les opérateurs  PAGEREF _Toc196727575 \h 23
 HYPERLINK \l "_Toc196727576" 4.7.1 L'affectation  PAGEREF _Toc196727576 \h 23
 HYPERLINK \l "_Toc196727577" 4.7.2 Les opérateurs arithmétiques  PAGEREF _Toc196727577 \h 23
 HYPERLINK \l "_Toc196727578" 4.7.3 Les opérateurs relationnels  PAGEREF _Toc196727578 \h 24
 HYPERLINK \l "_Toc196727579" 4.7.4 Les opérateurs logiques booléens  PAGEREF _Toc196727579 \h 24
 HYPERLINK \l "_Toc196727580" 4.7.5 Les opérateurs logiques bit à bit  PAGEREF _Toc196727580 \h 25
 HYPERLINK \l "_Toc196727581" 4.7.6 Les opérateurs d'affectation composée  PAGEREF _Toc196727581 \h 25
 HYPERLINK \l "_Toc196727582" 4.7.7 Les opérateurs d'incrémentation et de décrémentation  PAGEREF _Toc196727582 \h 25
 HYPERLINK \l "_Toc196727583" 4.7.8 L'opérateur virgule  PAGEREF _Toc196727583 \h 26
 HYPERLINK \l "_Toc196727584" 4.7.9 L'opérateur conditionnel ternaire  PAGEREF _Toc196727584 \h 26
 HYPERLINK \l "_Toc196727585" 4.7.10 L'opérateur de conversion de type  PAGEREF _Toc196727585 \h 26
 HYPERLINK \l "_Toc196727586" 4.7.11 L'opérateur adresse / pointeur / indirection  PAGEREF _Toc196727586 \h 26
 HYPERLINK \l "_Toc196727587" 4.7.12 Règles de priorité des opérateurs  PAGEREF _Toc196727587 \h 28
 HYPERLINK \l "_Toc196727588" 4.7.13 Les constantes chaînes de caractères  PAGEREF _Toc196727588 \h 29
 HYPERLINK \l "_Toc196727589" 4.8 Les instructions de branchement conditionnel  PAGEREF _Toc196727589 \h 29
 HYPERLINK \l "_Toc196727590" 4.8.1 Branchement conditionnel if... else  PAGEREF _Toc196727590 \h 30
 HYPERLINK \l "_Toc196727591" 4.8.2 Branchement multiple switch  PAGEREF _Toc196727591 \h 30
 HYPERLINK \l "_Toc196727592" 4.9 Les boucles  PAGEREF _Toc196727592 \h 31
 HYPERLINK \l "_Toc196727593" 4.9.1 Boucle while  PAGEREF _Toc196727593 \h 31
 HYPERLINK \l "_Toc196727594" 4.9.2 Boucle do... while  PAGEREF _Toc196727594 \h 31
 HYPERLINK \l "_Toc196727595" 4.9.3 Boucle for  PAGEREF _Toc196727595 \h 32
 HYPERLINK \l "_Toc196727596" 4.10 Les instructions de branchement non conditionnel  PAGEREF _Toc196727596 \h 32
 HYPERLINK \l "_Toc196727597" 4.10.1 Branchement non conditionnel break  PAGEREF _Toc196727597 \h 32
 HYPERLINK \l "_Toc196727598" 4.10.2 Branchement non conditionnel continue  PAGEREF _Toc196727598 \h 32
 HYPERLINK \l "_Toc196727599" 4.10.3 Branchement non conditionnel goto  PAGEREF _Toc196727599 \h 33
 HYPERLINK \l "_Toc196727600" 4.11 Les fonctions  PAGEREF _Toc196727600 \h 33
 HYPERLINK \l "_Toc196727601" 4.11.1 Définition d’une fonction  PAGEREF _Toc196727601 \h 33
 HYPERLINK \l "_Toc196727602" 4.11.2 Appel d'une fonction  PAGEREF _Toc196727602 \h 34
 HYPERLINK \l "_Toc196727603" 4.11.3 Déclaration d'une fonction  PAGEREF _Toc196727603 \h 34
 HYPERLINK \l "_Toc196727604" 4.11.4 Cas particulier de la fonction main()  PAGEREF _Toc196727604 \h 35
 HYPERLINK \l "_Toc196727605" 4.11.5 Pointeur sur une fonction  PAGEREF _Toc196727605 \h 35
 HYPERLINK \l "_Toc196727606" 4.11.6 Fonctions avec un nombre variable de paramètres  PAGEREF _Toc196727606 \h 36
 HYPERLINK \l "_Toc196727607" 4.12 Durée de vie des variables  PAGEREF _Toc196727607 \h 37
 HYPERLINK \l "_Toc196727608" 4.12.1 Variables globales  PAGEREF _Toc196727608 \h 38
 HYPERLINK \l "_Toc196727609" 4.12.2 Variables locales  PAGEREF _Toc196727609 \h 38
 HYPERLINK \l "_Toc196727610" 4.12.3 Transmission des paramètres d'une fonction  PAGEREF _Toc196727610 \h 39
 HYPERLINK \l "_Toc196727611" 4.12.4 Les qualificateurs de type const et volatile  PAGEREF _Toc196727611 \h 39
 HYPERLINK \l "_Toc196727612" 4.13 Les directives au préprocesseur  PAGEREF _Toc196727612 \h 40
 HYPERLINK \l "_Toc196727613" 4.13.1 La directive #include  PAGEREF _Toc196727613 \h 40
 HYPERLINK \l "_Toc196727614" 4.13.2 La directive #define  PAGEREF _Toc196727614 \h 40
 HYPERLINK \l "_Toc196727615" 4.13.3 La compilation conditionnelle  PAGEREF _Toc196727615 \h 42
 HYPERLINK \l "_Toc196727616" 4.14 Les bibliothèques standards  PAGEREF _Toc196727616 \h 43
 HYPERLINK \l "_Toc196727617" 4.15 Les conventions d'écriture d'un programme C  PAGEREF _Toc196727617 \h 44
 HYPERLINK \l "_Toc196727618" 4.16 Le C++  PAGEREF _Toc196727618 \h 44
 HYPERLINK \l "_Toc196727619" 4.16.1 Généralités  PAGEREF _Toc196727619 \h 44
 HYPERLINK \l "_Toc196727620" 4.16.2 Différences entre C et C++  PAGEREF _Toc196727620 \h 45
 HYPERLINK \l "_Toc196727621" 4.17 Travaux dirigés  PAGEREF _Toc196727621 \h 50
 HYPERLINK \l "_Toc196727622" 5 Introduction : architecture des ordinateurs  PAGEREF _Toc196727622 \h 54
 HYPERLINK \l "_Toc196727623" 5.1 Schéma de base  PAGEREF _Toc196727623 \h 54
 HYPERLINK \l "_Toc196727624" 5.2 Le microprocesseur (CPU)  PAGEREF _Toc196727624 \h 54
 HYPERLINK \l "_Toc196727625" 5.2.1 Présentation  PAGEREF _Toc196727625 \h 54
 HYPERLINK \l "_Toc196727626" 5.2.2 Fonctionnement  PAGEREF _Toc196727626 \h 54
 HYPERLINK \l "_Toc196727627" 5.2.3 Mémoire cache  PAGEREF _Toc196727627 \h 55
 HYPERLINK \l "_Toc196727628" 5.2.4 Signaux de commande  PAGEREF _Toc196727628 \h 56
 HYPERLINK \l "_Toc196727629" 5.2.5 Unités fonctionnelles  PAGEREF _Toc196727629 \h 56
 HYPERLINK \l "_Toc196727630" 5.2.6 Familles  PAGEREF _Toc196727630 \h 57
 HYPERLINK \l "_Toc196727631" 5.2.7 Jeu d'instruction, architecture de CPU  PAGEREF _Toc196727631 \h 57
 HYPERLINK \l "_Toc196727632" 5.2.8 Améliorations technologiques  PAGEREF _Toc196727632 \h 58
 HYPERLINK \l "_Toc196727633" 5.3 Le bus  PAGEREF _Toc196727633 \h 59
 HYPERLINK \l "_Toc196727634" 5.3.1 Description  PAGEREF _Toc196727634 \h 59
 HYPERLINK \l "_Toc196727635" 5.3.2 Matériel  PAGEREF _Toc196727635 \h 60
 HYPERLINK \l "_Toc196727636" 5.3.3 Dans un ordinateur  PAGEREF _Toc196727636 \h 61
 HYPERLINK \l "_Toc196727637" 5.4 Le chipset  PAGEREF _Toc196727637 \h 61
 HYPERLINK \l "_Toc196727638" 5.5 La mémoire  PAGEREF _Toc196727638 \h 62
 HYPERLINK \l "_Toc196727639" 5.5.1 Caractéristiques techniques  PAGEREF _Toc196727639 \h 62
 HYPERLINK \l "_Toc196727640" 5.5.2 Temps d'accès et capacité des différents types de mémoire  PAGEREF _Toc196727640 \h 63
 HYPERLINK \l "_Toc196727641" 5.6 Communication périphériques/CPU  PAGEREF _Toc196727641 \h 63
 HYPERLINK \l "_Toc196727642" 5.6.1 Les interruptions matérielles (et IRQ)  PAGEREF _Toc196727642 \h 63
 HYPERLINK \l "_Toc196727643" 5.6.2 Les adresses de base  PAGEREF _Toc196727643 \h 64
 HYPERLINK \l "_Toc196727644" 5.6.3 Utilisation d’un canal DMA  PAGEREF _Toc196727644 \h 64
 HYPERLINK \l "_Toc196727645" 6 Le système d’exploitation  PAGEREF _Toc196727645 \h 65
 HYPERLINK \l "_Toc196727646" 6.1 Définition  PAGEREF _Toc196727646 \h 65
 HYPERLINK \l "_Toc196727647" 6.2 Structure générale  PAGEREF _Toc196727647 \h 65
 HYPERLINK \l "_Toc196727648" 6.3 Les différents types de systèmes d’exploitation  PAGEREF _Toc196727648 \h 67
 HYPERLINK \l "_Toc196727649" 6.3.1 Les systèmes à traitements par lots  PAGEREF _Toc196727649 \h 67
 HYPERLINK \l "_Toc196727650" 6.3.2 Les systèmes interactifs  PAGEREF _Toc196727650 \h 67
 HYPERLINK \l "_Toc196727651" 6.3.3 Les systèmes « temps-réel »  PAGEREF _Toc196727651 \h 68
 HYPERLINK \l "_Toc196727652" 6.4 Le noyau  PAGEREF _Toc196727652 \h 68
 HYPERLINK \l "_Toc196727653" 6.4.1 Définition  PAGEREF _Toc196727653 \h 68
 HYPERLINK \l "_Toc196727654" 6.4.2 Les différents types de noyaux  PAGEREF _Toc196727654 \h 69
 HYPERLINK \l "_Toc196727655" 6.4.3 Avantages et inconvénients des différents types de noyau  PAGEREF _Toc196727655 \h 70
 HYPERLINK \l "_Toc196727656" 6.5 Linux  PAGEREF _Toc196727656 \h 71
 HYPERLINK \l "_Toc196727657" 6.5.1 Structure de l’OS Linux  PAGEREF _Toc196727657 \h 71
 HYPERLINK \l "_Toc196727658" 6.5.2 Quelques notions fondamentales  PAGEREF _Toc196727658 \h 72
 HYPERLINK \l "_Toc196727659" 6.5.3 La commutation de contexte  PAGEREF _Toc196727659 \h 72
 HYPERLINK \l "_Toc196727660" 6.5.4 Principe de gestion des interruptions matérielles et logicielles  PAGEREF _Toc196727660 \h 74
 HYPERLINK \l "_Toc196727661" 6.5.5 Prise en compte d’une interruption matérielle  PAGEREF _Toc196727661 \h 75
 HYPERLINK \l "_Toc196727662" 6.5.6 Gestion des exceptions (trappes)  PAGEREF _Toc196727662 \h 76
 HYPERLINK \l "_Toc196727663" 6.5.7 Exécution d’une fonction du système  PAGEREF _Toc196727663 \h 77
 HYPERLINK \l "_Toc196727664" 6.5.8 Imbrication de la prise en compte des interruptions  PAGEREF _Toc196727664 \h 78
 HYPERLINK \l "_Toc196727665" 7 Le « multitâche » en pratique  PAGEREF _Toc196727665 \h 79
 HYPERLINK \l "_Toc196727666" 7.1 Les processus  PAGEREF _Toc196727666 \h 79
 HYPERLINK \l "_Toc196727667" 7.2 Création d’un processus sous Linux  PAGEREF _Toc196727667 \h 81
 HYPERLINK \l "_Toc196727668" 7.2.1 La fonction fork()  PAGEREF _Toc196727668 \h 81
 HYPERLINK \l "_Toc196727669" 7.2.2 Les fonctions de gestion des identifiants de processus  PAGEREF _Toc196727669 \h 82
 HYPERLINK \l "_Toc196727670" 7.2.3 Optimisation de fork() : le « copy on write »  PAGEREF _Toc196727670 \h 82
 HYPERLINK \l "_Toc196727671" 7.2.4 Les processus zombies (et comment les éviter)  PAGEREF _Toc196727671 \h 83
 HYPERLINK \l "_Toc196727672" 7.2.5 Les fonctions de recouvrement  PAGEREF _Toc196727672 \h 87
 HYPERLINK \l "_Toc196727673" 7.3 Les threads (ou processus légers)  PAGEREF _Toc196727673 \h 90
 HYPERLINK \l "_Toc196727674" 7.3.1 Principe des threads  PAGEREF _Toc196727674 \h 90
 HYPERLINK \l "_Toc196727675" 7.3.2 Implémentation des threads au niveau utilisateur  PAGEREF _Toc196727675 \h 91
 HYPERLINK \l "_Toc196727676" 7.3.3 Implémentation des threads au niveau noyau  PAGEREF _Toc196727676 \h 92
 HYPERLINK \l "_Toc196727677" 7.3.4 Fonctions système liées aux threads  PAGEREF _Toc196727677 \h 92
 HYPERLINK \l "_Toc196727678" 7.4 L’ordonnancement (le « scheduler »)  PAGEREF _Toc196727678 \h 95
 HYPERLINK \l "_Toc196727679" 7.4.1 Rappels sur la commutation de contexte  PAGEREF _Toc196727679 \h 95
 HYPERLINK \l "_Toc196727680" 7.4.2 La politique du « premier arrivé, premier servi »  PAGEREF _Toc196727680 \h 96
 HYPERLINK \l "_Toc196727681" 7.4.3 La politique par priorité  PAGEREF _Toc196727681 \h 96
 HYPERLINK \l "_Toc196727682" 7.4.4 La politique du tourniquet (round robin)  PAGEREF _Toc196727682 \h 97
 HYPERLINK \l "_Toc196727683" 7.4.5 Les politiques d’ordonnancement sous Linux  PAGEREF _Toc196727683 \h 97
 HYPERLINK \l "_Toc196727684" 8 Le démarrage d’un système Linux  PAGEREF _Toc196727684 \h 100
 HYPERLINK \l "_Toc196727685" 8.1 Le chargeur de noyau  PAGEREF _Toc196727685 \h 100
 HYPERLINK \l "_Toc196727686" 8.2 Le processus « init »  PAGEREF _Toc196727686 \h 100
 HYPERLINK \l "_Toc196727687" 8.3 Les niveaux d'exécution  PAGEREF _Toc196727687 \h 102
 HYPERLINK \l "_Toc196727688" 8.4 L’arborescence des processus  PAGEREF _Toc196727688 \h 104
 HYPERLINK \l "_Toc196727689" 9 Les signaux  PAGEREF _Toc196727689 \h 106
 HYPERLINK \l "_Toc196727690" 9.1 Présentation  PAGEREF _Toc196727690 \h 106
 HYPERLINK \l "_Toc196727691" 9.2 Les signaux classiques  PAGEREF _Toc196727691 \h 106
 HYPERLINK \l "_Toc196727692" 9.2.1 L’envoi d’un signal  PAGEREF _Toc196727692 \h 107
 HYPERLINK \l "_Toc196727693" 9.2.2 La prise en compte d’un signal  PAGEREF _Toc196727693 \h 108
 HYPERLINK \l "_Toc196727694" 9.2.3 Signaux et appels système  PAGEREF _Toc196727694 \h 109
 HYPERLINK \l "_Toc196727695" 9.3 Les routines systèmes liées aux signaux  PAGEREF _Toc196727695 \h 110
 HYPERLINK \l "_Toc196727696" 9.3.1 Envoyer un signal à un processus  PAGEREF _Toc196727696 \h 110
 HYPERLINK \l "_Toc196727697" 9.3.2 Bloquer les signaux  PAGEREF _Toc196727697 \h 111
 HYPERLINK \l "_Toc196727698" 9.3.3 Attacher un handler à un signal  PAGEREF _Toc196727698 \h 114
 HYPERLINK \l "_Toc196727699" 9.3.4 Traiter les appels systèmes interrompus  PAGEREF _Toc196727699 \h 118
 HYPERLINK \l "_Toc196727700" 9.3.5 Attendre un signal  PAGEREF _Toc196727700 \h 118
 HYPERLINK \l "_Toc196727701" 9.3.6 Armer une temporisation  PAGEREF _Toc196727701 \h 118
 HYPERLINK \l "_Toc196727702" 9.4 Les signaux temps réel  PAGEREF _Toc196727702 \h 119
 HYPERLINK \l "_Toc196727703" 9.4.1 Présentation  PAGEREF _Toc196727703 \h 119
 HYPERLINK \l "_Toc196727704" 9.4.2 Envoyer un signal temps réel  PAGEREF _Toc196727704 \h 120
 HYPERLINK \l "_Toc196727705" 9.4.3 Attacher un handler à un signal temps réel  PAGEREF _Toc196727705 \h 121
 HYPERLINK \l "_Toc196727706" 9.4.4 Exécution du gestionnaire de signal  PAGEREF _Toc196727706 \h 122
 HYPERLINK \l "_Toc196727707" 9.4.5 Complément sur les signaux temps-réels  PAGEREF _Toc196727707 \h 123
 HYPERLINK \l "_Toc196727708" 10 Communication centralisée inter-processus  PAGEREF _Toc196727708 \h 125
 HYPERLINK \l "_Toc196727709" 10.1 Les tubes (pipes)  PAGEREF _Toc196727709 \h 125
 HYPERLINK \l "_Toc196727710" 10.1.1 Les tubes anonymes  PAGEREF _Toc196727710 \h 125
 HYPERLINK \l "_Toc196727711" 10.1.2 Les tubes nommés  PAGEREF _Toc196727711 \h 131
 HYPERLINK \l "_Toc196727712" 10.2 Caractéristiques communes aux IPCs  PAGEREF _Toc196727712 \h 138
 HYPERLINK \l "_Toc196727713" 10.3 Les files de messages (messages queues/MSQ)  PAGEREF _Toc196727713 \h 139
 HYPERLINK \l "_Toc196727714" 10.4 Les régions de mémoire partagée  PAGEREF _Toc196727714 \h 146
 HYPERLINK \l "_Toc196727715" 11 La communication répartie  PAGEREF _Toc196727715 \h 155
 HYPERLINK \l "_Toc196727716" 11.1 Le modèle client-serveur  PAGEREF _Toc196727716 \h 155
 HYPERLINK \l "_Toc196727717" 11.2 Quelques rappels réseau  PAGEREF _Toc196727717 \h 156
 HYPERLINK \l "_Toc196727718" 11.3 Les fonctions et structures propres à TCP/IP  PAGEREF _Toc196727718 \h 158
 HYPERLINK \l "_Toc196727719" 11.3.1 La normalisation des entiers (endianness)  PAGEREF _Toc196727719 \h 158
 HYPERLINK \l "_Toc196727720" 11.3.2 La résolution de nom  PAGEREF _Toc196727720 \h 159
 HYPERLINK \l "_Toc196727721" 11.3.3 La résolution de service  PAGEREF _Toc196727721 \h 161
 HYPERLINK \l "_Toc196727722" 11.4 La communication par datagrammes  PAGEREF _Toc196727722 \h 162
 HYPERLINK \l "_Toc196727723" 11.5 La communication en mode connecté  PAGEREF _Toc196727723 \h 162
 HYPERLINK \l "_Toc196727724" 11.6 Manuel de l’API des socket  PAGEREF _Toc196727724 \h 163
 HYPERLINK \l "_Toc196727725" 12 Les problématiques de synchronisation  PAGEREF _Toc196727725 \h 177
 HYPERLINK \l "_Toc196727726" 12.1 Problématique  PAGEREF _Toc196727726 \h 177
 HYPERLINK \l "_Toc196727727" 12.2 L’exclusion mutuelle  PAGEREF _Toc196727727 \h 177
 HYPERLINK \l "_Toc196727728" 12.2.1 Exemple de problématique  PAGEREF _Toc196727728 \h 177
 HYPERLINK \l "_Toc196727729" 12.2.2 Recherche de solutions à l’exclusion mutuelle  PAGEREF _Toc196727729 \h 178
 HYPERLINK \l "_Toc196727730" 12.3 L’allocation de ressources – les sémaphores  PAGEREF _Toc196727730 \h 180
 HYPERLINK \l "_Toc196727731" 12.3.1 Principe  PAGEREF _Toc196727731 \h 180
 HYPERLINK \l "_Toc196727732" 12.3.2 Le danger des sémaphores : l’interblocage  PAGEREF _Toc196727732 \h 182
 HYPERLINK \l "_Toc196727733" 12.3.3 Les sémaphores sous Linux  PAGEREF _Toc196727733 \h 183
 HYPERLINK \l "_Toc196727734" 12.4 Les lecteurs-rédacteurs  PAGEREF _Toc196727734 \h 187
 HYPERLINK \l "_Toc196727735" 12.4.1 Principe  PAGEREF _Toc196727735 \h 187
 HYPERLINK \l "_Toc196727736" 12.4.2 Les verrous de fichiers sous Linux  PAGEREF _Toc196727736 \h 189
 HYPERLINK \l "_Toc196727737" 12.5 Le schéma producteur-consommateur  PAGEREF _Toc196727737 \h 190
 HYPERLINK \l "_Toc196727738" 12.5.1 Principe et résolution pour 1 producteur et 1 consommateur  PAGEREF _Toc196727738 \h 190
 HYPERLINK \l "_Toc196727739" 12.5.2 Extension du problème à X producteurs et Y consommateurs  PAGEREF _Toc196727739 \h 191
 HYPERLINK \l "_Toc196727740" 12.6 L’exclusion mutuelle chez les thread  PAGEREF _Toc196727740 \h 192
 HYPERLINK \l "_Toc196727741" 12.6.1 Les mutex  PAGEREF _Toc196727741 \h 192
 HYPERLINK \l "_Toc196727742" 12.6.2 Les variables conditions  PAGEREF _Toc196727742 \h 193
 HYPERLINK \l "_Toc196727743" 12.7 Autres problématiques d’interblocages  PAGEREF _Toc196727743 \h 194
 HYPERLINK \l "_Toc196727744" 12.7.1 Le dîner des philosophes  PAGEREF _Toc196727744 \h 194
 HYPERLINK \l "_Toc196727745" 12.7.2 L'algorithme du banquier  PAGEREF _Toc196727745 \h 194
 HYPERLINK \l "_Toc196727746" 13 La gestion de la mémoire  PAGEREF _Toc196727746 \h 196
 HYPERLINK \l "_Toc196727747" 13.1 Rappels  PAGEREF _Toc196727747 \h 196
 HYPERLINK \l "_Toc196727748" 13.2 Espace d’adressage  PAGEREF _Toc196727748 \h 196
 HYPERLINK \l "_Toc196727749" 13.3 La segmentation  PAGEREF _Toc196727749 \h 197
 HYPERLINK \l "_Toc196727750" 13.4 La pagination  PAGEREF _Toc196727750 \h 198
 HYPERLINK \l "_Toc196727751" 13.5 Protection des accès mémoire entre processus  PAGEREF _Toc196727751 \h 200
 HYPERLINK \l "_Toc196727752" 13.6 La pagination multiniveaux  PAGEREF _Toc196727752 \h 201
 HYPERLINK \l "_Toc196727753" 13.7 Mémoire virtuelle – swap  PAGEREF _Toc196727753 \h 202
 HYPERLINK \l "_Toc196727754" 13.7.1 Principe  PAGEREF _Toc196727754 \h 202
 HYPERLINK \l "_Toc196727755" 13.7.2 L’algorithme optimal  PAGEREF _Toc196727755 \h 203
 HYPERLINK \l "_Toc196727756" 13.7.3 L’algorithme FIFO  PAGEREF _Toc196727756 \h 203
 HYPERLINK \l "_Toc196727757" 13.7.4 L’algorithme LRU  PAGEREF _Toc196727757 \h 203
 HYPERLINK \l "_Toc196727758" 13.7.5 L’algorithme de la seconde chance  PAGEREF _Toc196727758 \h 204
 HYPERLINK \l "_Toc196727759" 13.7.6 L’algorithme LFU  PAGEREF _Toc196727759 \h 204
 HYPERLINK \l "_Toc196727760" 13.7.7 Anomalie de Belady  PAGEREF _Toc196727760 \h 204
 HYPERLINK \l "_Toc196727761" 13.8 Application : la gestion de mémoire sous Linux  PAGEREF _Toc196727761 \h 205
 HYPERLINK \l "_Toc196727762" 13.8.1 Les régions  PAGEREF _Toc196727762 \h 205
 HYPERLINK \l "_Toc196727763" 13.8.2 La gestion de la pagination  PAGEREF _Toc196727763 \h 205
 HYPERLINK \l "_Toc196727764" 13.8.3 La gestion de l’espace d’adressage  PAGEREF _Toc196727764 \h 206
 HYPERLINK \l "_Toc196727765" 13.9 Les algorithmes d’allocation mémoire  PAGEREF _Toc196727765 \h 209
 HYPERLINK \l "_Toc196727766" 13.9.1 Principes généraux  PAGEREF _Toc196727766 \h 209
 HYPERLINK \l "_Toc196727767" 13.9.2 Implémentation sous Linux  PAGEREF _Toc196727767 \h 209
 HYPERLINK \l "_Toc196727768" 14 Systèmes de fichiers et implémentation  PAGEREF _Toc196727768 \h 211
 HYPERLINK \l "_Toc196727769" 14.1 Introduction  PAGEREF _Toc196727769 \h 211
 HYPERLINK \l "_Toc196727770" 14.2 Le fichier logique  PAGEREF _Toc196727770 \h 213
 HYPERLINK \l "_Toc196727771" 14.3 Généralités sur la résolution de nom  PAGEREF _Toc196727771 \h 213
 HYPERLINK \l "_Toc196727772" 14.4 Le fichier physique  PAGEREF _Toc196727772 \h 214
 HYPERLINK \l "_Toc196727773" 14.4.1 Le disque dur  PAGEREF _Toc196727773 \h 214
 HYPERLINK \l "_Toc196727774" 14.4.2 Les méthodes d’allocation des mémoires secondaires  PAGEREF _Toc196727774 \h 215
 HYPERLINK \l "_Toc196727775" 14.4.3 La gestion de l’espace libre  PAGEREF _Toc196727775 \h 216
 HYPERLINK \l "_Toc196727776" 14.4.4 Les partitions  PAGEREF _Toc196727776 \h 217
 HYPERLINK \l "_Toc196727777" 14.4.5 Le montage d’une partition  PAGEREF _Toc196727777 \h 217
 HYPERLINK \l "_Toc196727778" 14.5 Exemple de système de gestion de fichier : ext2  PAGEREF _Toc196727778 \h 218
 HYPERLINK \l "_Toc196727779" 14.5.1 La structure d’i-node  PAGEREF _Toc196727779 \h 218
 HYPERLINK \l "_Toc196727780" 14.5.2 Les droits classiques sur les fichiers sous Unix/Linux  PAGEREF _Toc196727780 \h 219
 HYPERLINK \l "_Toc196727781" 14.5.3 Liens physiques et liens symboliques  PAGEREF _Toc196727781 \h 220
 HYPERLINK \l "_Toc196727782" 14.5.4 L’allocation des blocs de données  PAGEREF _Toc196727782 \h 220
 HYPERLINK \l "_Toc196727783" 14.5.5 Structure des partitions  PAGEREF _Toc196727783 \h 221
 HYPERLINK \l "_Toc196727784" 14.6 Le système de gestion de fichiers virtuel VFS  PAGEREF _Toc196727784 \h 223
 HYPERLINK \l "_Toc196727785" 14.6.1 Introduction  PAGEREF _Toc196727785 \h 223
 HYPERLINK \l "_Toc196727786" 14.6.2 Structures et fonctionnement de VFS  PAGEREF _Toc196727786 \h 223
 HYPERLINK \l "_Toc196727787" 14.6.3 Accès à VFS par un processus  PAGEREF _Toc196727787 \h 224
 HYPERLINK \l "_Toc196727788" 14.6.4 Le fonctionnement du cache des dentry (dcache)  PAGEREF _Toc196727788 \h 225
 HYPERLINK \l "_Toc196727789" 14.6.5 Le cache des blocs disque (buffer cache)  PAGEREF _Toc196727789 \h 226
 HYPERLINK \l "_Toc196727790" 14.7 Les opérations sur les fichiers  PAGEREF _Toc196727790 \h 227
 HYPERLINK \l "_Toc196727791" 14.7.1 L’ouverture d’un fichier  PAGEREF _Toc196727791 \h 227
 HYPERLINK \l "_Toc196727792" 14.7.2 La fermeture d’un fichier  PAGEREF _Toc196727792 \h 232
 HYPERLINK \l "_Toc196727793" 14.7.3 La lecture et l’écriture dans un fichier  PAGEREF _Toc196727793 \h 233
 HYPERLINK \l "_Toc196727794" 14.7.4 Se positionner dans un fichier  PAGEREF _Toc196727794 \h 235
 HYPERLINK \l "_Toc196727795" 14.7.5 Manipuler les attributs des fichiers  PAGEREF _Toc196727795 \h 236
 HYPERLINK \l "_Toc196727796" 14.7.6 Réaliser des opérations sur des fichiers  PAGEREF _Toc196727796 \h 239
 HYPERLINK \l "_Toc196727797" 14.7.7 Création/suppression de liens  PAGEREF _Toc196727797 \h 239
 HYPERLINK \l "_Toc196727798" 14.7.8 Modification et tests des droits d’un fichier  PAGEREF _Toc196727798 \h 240
 HYPERLINK \l "_Toc196727799" 14.7.9 Modification du propriétaire d’un fichier  PAGEREF _Toc196727799 \h 243
 HYPERLINK \l "_Toc196727800" 14.8 Les opérations sur les répertoires  PAGEREF _Toc196727800 \h 243
 HYPERLINK \l "_Toc196727801" 14.8.1 Changer de répertoire courant  PAGEREF _Toc196727801 \h 243
 HYPERLINK \l "_Toc196727802" 14.8.2 Changer de répertoire racine  PAGEREF _Toc196727802 \h 244
 HYPERLINK \l "_Toc196727803" 14.8.3 Création d’un répertoire  PAGEREF _Toc196727803 \h 245
 HYPERLINK \l "_Toc196727804" 14.8.4 Destruction d’un répertoire  PAGEREF _Toc196727804 \h 245
 HYPERLINK \l "_Toc196727805" 14.8.5 Exploration d’un répertoire  PAGEREF _Toc196727805 \h 245
 HYPERLINK \l "_Toc196727806" 14.9 Les opérations diverses  PAGEREF _Toc196727806 \h 247
 HYPERLINK \l "_Toc196727807" 14.9.1 Les opération sur les liens symboliques  PAGEREF _Toc196727807 \h 247
 HYPERLINK \l "_Toc196727808" 14.9.2 Les opérations sur les partitions  PAGEREF _Toc196727808 \h 248
 HYPERLINK \l "_Toc196727809" 14.10 Le système de fichier /proc  PAGEREF _Toc196727809 \h 252
 HYPERLINK \l "_Toc196727810" 15 Les entrées-sorties  PAGEREF _Toc196727810 \h 253
 HYPERLINK \l "_Toc196727811" 15.1 Principes  PAGEREF _Toc196727811 \h 253
 HYPERLINK \l "_Toc196727812" 15.1.1 Le contrôleur d’entrées-sorties  PAGEREF _Toc196727812 \h 253
 HYPERLINK \l "_Toc196727813" 15.1.2 Le pilote  PAGEREF _Toc196727813 \h 253
 HYPERLINK \l "_Toc196727814" 15.1.3 Ordonnancement des requêtes des pilotes  PAGEREF _Toc196727814 \h 254
 HYPERLINK \l "_Toc196727815" 15.2 Les entrées-sorties sous Linux  PAGEREF _Toc196727815 \h 256
 HYPERLINK \l "_Toc196727816" 15.2.1 Fichiers spéciaux  PAGEREF _Toc196727816 \h 256
 HYPERLINK \l "_Toc196727817" 15.2.2 Opérations de contrôle sur un périphérique  PAGEREF _Toc196727817 \h 259
 HYPERLINK \l "_Toc196727818" 15.2.3 Multiplexage des entrées-sorties  PAGEREF _Toc196727818 \h 259

Programme officiel
Public concerné et conditions d’accès
Avoir des bases sur le fonctionnement des systèmes d'exploitation (cette UE intervient dans des diplômes et certifications de niveau supérieur à Bac + 2).

Finalités de l’unité d’enseignement
Objectifs pédagogiques
Approches qualitative et quantitative des systèmes d'exploitation et de communication. Conception et fonctionnement des systèmes d'exploitation centralisés et répartis, spécificités des systèmes temps réels. Introduction à la programmation système.
Exemples dans les systèmes UNIX, LINUX et LINUX-RT
Capacité et compétences acquises
Savoir développer une application multi-processus utilisant des outils de communication et de synchronisation en C sous Linux/Unix.
Appréhender les mécanismes fondamentaux des systèmes d'exploitation Comprendre la problématique des systèmes temps réels et les particularités de ces systèmes
Organisation
Description des heures d’enseignements
Cours : 60 heures (Nancy : 51 heures).
Modalités de validation
Examen final (pour Nancy : projet = ¼, examen final = ¾, Cf. réforme 2006-2007).

Contenu de la formation
Introduction générale
Structure des systèmes informatiques.
Structure des systèmes d'exploitation.
Spécificités des systèmes temps réel
Gestion de processus
Processus : concepts, opérations sur les processus. Processus coopératifs, threads, communications inter-processus (tubes, files de messages, segments de mémoire partagée).
Ordonnancement de l'unité centrale
Concepts et critères d'ordonnancement.
Ordonnancement temps réel
Synchronisation de processus
Section critique, sémaphores, problèmes classiques.
Interblocage, inversion de priorités
Prévention, détection, correction, héritage de priorités...
Gestion de la mémoire
pagination, segmentation. Mémoire virtuelle.
Systèmes de fichiers
Interfaces des systèmes de fichiers et implémentation.
Systèmes distribués
Structure des réseaux et structure des systèmes répartis. Programmation socket
Exemple d'un système : LINUX, LINUX-RT
Bibliographie
AuteurTitreJoëlle Delacroix*Linux : programmation système et réseau, Dunod 2003Nils SchaeferProgrammation système sous Unix, sN InformatiqueAndrew TanenbaumSystèmes d’exploitation, Pearsoneducation 2003Jean-Marie RiffletLa programmation sous Unix - 3ème édition, Ediscience 1993Jean-Marie RiffletLa communication sous Unix - 2ème édition, Ediscience 1994(*) : le livre de Joëlle Delacroix est le seul livre de la bibliographie officielle du CNAM.
Contacts
Coordonnées du secrétariat du responsable national :
Accès 37 0 36Case courrier : 432
Service d'Informatique cycle A - 2 rue Conté - Paris 3e
Tél : 01 40 27 27 02 - Fax : 01 58 80 84 93
Contact : Virginie Moreau et Françoise Carrasse Courriel :  HYPERLINK "mailto:sec-cycleA.informatique@cnam.fr" sec-cycleA.informatique@cnam.fr
Coordonnées du responsable de cette formation à NANCY :
M. Emmanuel DESVIGNE
Tel : 06 33 65 13 35
Courriel :  HYPERLINK "mailto:emmanuel@desvigne.org" emmanuel@desvigne.org
URL des cours :  HYPERLINK "http://cours.desvigne.org/" http://cours.desvigne.org/
Nouveautés à partir de la session 2006-2007
Origine de la réforme
Suite à des discussions avec la CTI (commission des titres de l'ingénieur) et ses équivalents pour la Licence et les titres RNCP, le CNAM doit garantir que les programmes enseignés de partout en France sont identiques. Pour cela, il a été crée un "référentiel de cours" plus efficace que les simples descriptions d'UE en une page auxquelles nous étions habitués.
Un site "http://ne.pleiad.net" regroupe ces infos (à destination des formateurs) pour les 4 cours expérimentés cette année : RSX101, RSX102, NSY103, et NFP107.
Résumé du principe de la réforme
Les formateurs seront invités à déposer/proposer un sujet d'examen. Le coordinateur du cours pour le Nord-Est gèrera une "discussion" visant à faire émerger UN seul sujet pour tout le Nord-Est. Ce sujet est ensuite transmis au Professeur responsable du cours au niveau national (à Paris) qui donne son accord ou refuse le sujet en suggérant des modifications.
Il est demandé aux enseignants de suivre le plan du cours et de participer à la discussion avec les autres enseignants du Nord-Est faisant le même cours que vous au même semestre.
Pour vos cours, le référentiel est maintenant en place. Il va donc être plus facile de travailler dès le début en harmonie avec la réforme. Logiquement ce plan de cours doit être proche des vôtres. Il ne devrait varier que dans la chronologie et l'enveloppe horaire consacrée à chaque partie (représentative des questions qui seront posées et des points associés).
En résumé : le programme est imposé, mais le sujet doit faire l'objet d'une discussion commune.
Plan imposé par cette réforme pour le cours NSY103
Introduction
THEME 1 : Rappels d'architecture machine (interruptions, fonctionnement de caches)
Structure des systèmes d'exploitation. Notions de bases (commutation de contexte, trappes,
appels système)

Gestion de processus
THEME 2 : Processus : concepts, opérations sur les processus.
THEME 3 : Processus Linux : création d’un processus, recouvrement de code, fin de
processus, états et structure d’un processus Linux. (fork, exec, wait, exit.)
THEME 4 : Concepts et critères d'ordonnancement de l’unité centrale. Algorithmes usuels.
Notion de préemption. Ordonnancement sous Linux. Fonctionnement des signaux.
Communication entre processus
THEME 5 : Communication centralisée : outils Linux (tubes anonymes, files de messages)
THEME 6 : Communication répartie : les sockets
THEME 7 : Les schémas de synchronisation : exclusion mutuelle,
producteurs/consommateurs, sémaphores.

Gestion de la mémoire
THEME 7 : Pagination. Mémoire virtuelle. Segments de mémoire partagé sous Linux.

Systèmes de fichiers
THEME 8 : Interfaces des systèmes de fichiers et implémentation. Allocation du support de
masse. Notions de répertoires, de partition. Gestion des accès disque (politique
d’ordonnancement du bras)
THEME 9 : Systèmes de gestion de fichiers sous Linux (inode, structure d’un fichier Linux,
structure d’une partition Linux, commandes Linux liées à la gestion de fichiers)

THEME 10 : Révision

Bibliographie
Joëlle Delacroix Linux : programmation système et réseau, Dunod 2003

Référentiel d’évaluation : L’évaluation de première et deuxième session est axée autour :
1/ d’un projet de mise en œuvre des outils de communication est donné à réaliser aux
auditeurs. Ce projet conduit à la spécification et programmation d’une application
multiprocessus simple communicant via les outils étudiés (tubes, MSQ, sockets, etc…).
Ce projet est obligatoire ; il compte pour un quart de la note finale de première et deuxième
session.
2/ d’un examen écrit comptant pour ¾ de la note finale.Mise à niveau en C/C++
La majorité des systèmes d’exploitation modernes sont écrits dans le langage C et/ou en C++. Les travaux pratiques/travaux dirigés de ce cours demanderont à connaître ces langages. Il serait irraisonnable d’espérer obtenir ce module NSY103 en faisant l’impasse de la maîtrise du C (et d’avoir quelques notions de C++).
Aussi, ce chapitre doit permettre à chacun de voir ou de revoir les principes et la syntaxe de ces langages.
Bref historique du C
Le C est un langage procédural conçu en 1972 par Dennis Richie et Ken Thompson, chercheurs aux Bell Labs, afin de développer un système d'exploitation : UNIX sur un DEC PDP-11.
En 1978, Brian Kernighan et Dennis Richie publient la définition classique du C dans le livre « The C Programming language ». Le C devenant de plus en plus populaire dans les années 80, plusieurs groupes mirent sur le marché des compilateurs comportant des extensions particulières.
En 1983, l'ANSI (American National Standards Institute) décida de normaliser le langage ; ce travail s'acheva en 1989 par la définition de la norme ANSI C. Celle-ci fut reprise telle quelle par l'ISO (International Standards Organization) en 1990.
La compilation
Le C est un langage compilé : le code (compréhensible par un être humain) doit être passé dans une moulinette (le compilateur) qui transformera ce code source en code exécutable directement par le microprocesseur (nous y reviendrons, c’est justement un point important de ce cour). Classiquement, la compilation se décompose en fait en 4 phases successives :
Le traitement par le préprocesseur (preprocessing) : le fichier source est analysé par le « préprocesseur » qui effectue des transformations purement textuelles (remplacement de chaînes de caractères, inclusion d'autres fichiers sources ...). Le résultat de ce prétraitement est toujours du C ;
La compilation : la compilation traduit le texte généré par le préprocesseur en assembleur, c'est-à-dire en une suite d'instructions du microprocesseur qui utilisent des « mnémoniques » rendant la lecture possible par un être humain ;
L'assemblage : cette opération transforme le code assembleur en un fichier binaire, c'est-à-dire en instructions directement compréhensibles par le processeur. Généralement, la compilation et l'assemblage se font dans la foulée, sauf si l'on spécifie explicitement que l'on veut le code assembleur. Le fichier produit par l'assemblage est appelé « fichier objet » ;
L'édition de liens : un programme est souvent séparé en plusieurs fichiers source, pour des raisons de clarté mais aussi parce qu'il fait généralement appel à des librairies de fonctions standard déjà écrites. Une fois chaque code source assemblé, il faut donc lier entre eux les différents fichiers objets. L'édition de liens produit alors un fichier dit exécutable.
Par convention, les différents types de fichiers utilisés lors de la compilation sont distingués par leur suffixe. Les fichiers source sont suffixés par .c, les fichiers prétraités par le préprocesseur par .i, les fichiers assembleur par .s, et les fichiers objet par .o. Les fichiers objets correspondant aux bibliothèques pré-compilées ont pour suffixe « .a ». Enfin, sous Unix/Linux, les exécutables produits n’ont pas de suffixe (« .com » ou « .exe » sous Windows).
Remarque importante (sous réserve de se faire taper sur les doigts par les puristes) : afin de ne pas réinventer la roue à chaque projet, certaines fonctions et routines sont compilées en fichiers objets (extension « .o »), puis classées dans des fichiers d’archives (extension « .a ») appelés « bibliothèques » en français (libraries en anglais). Il est interdit de traduire le mot anglais « library » en « librairie », mais bien en « bibliothèque ».
A noter qu’il existe une version moderne des bibliothèques : classiquement, lors de l’édition de liens, toutes les fonctions et routines utilisées par un programme étaient ajoutées à l’intérieur même de du fichier exécutable. Ainsi, si 10 programmes qui utilisent la même bibliothèque étaient exécutés en parallèle, chaque programme chargé en mémoire contient le même bout de code (ce qui prend inutilement de la place). Aujourd’hui, les fonctions qui sont mutualisées sont rangées dans des « bibliothèque dynamiques partagées ». On parlera de « shared library » sous Unix/Linux (suffixe « .so ») ou de « dynamically linked library » (suffixe « .dll ») sous Windows.
Classiquement, le compilateur C sous UNIX s'appelle cc. Il existe des alternatives, comme le compilateur du projet GNU : gcc. Ce compilateur peut-être obtenu gratuitement avec sa documentation et ses sources. Par défaut, gcc active toutes les étapes de la compilation. On le lance par la commande
gcc [options] fichier.c [-llibrairies]
Par défaut, le fichier exécutable s'appelle a.out. Le nom de l'exécutable peut être modifié à l'aide de l'option -o.
De façon classique (sans l’utilisation de bibliothèque dynamique partagée), les éventuelles bibliothèques sont déclarées par l’option -lbibliothèque. Dans ce cas, le système recherche le fichier bibliothèque.a dans le répertoire contenant les bibliothèques pré-compilées (généralement /usr/lib/ sous Unix/Linux). Par exemple, pour lier le programme avec la librairie mathématique, on spécifie -lm. Le fichier objet correspondant est libm.a. Lorsque les librairies pré-compilées ne se trouvent pas dans le répertoire usuel, on spécifie leur chemin d'accès par l'option -L.
Les options les plus importantes du compilateur gcc sont les suivantes :
-c : supprime l'édition de liens ; produit un fichier objet ;
-E : n'active que le préprocesseur (le résultat est envoyé sur la sortie standard) ;
-g : produit des informations symboliques nécessaires au débogueur ;
-Inom-de-répertoire : spécifie le répertoire dans lequel doivent être recherchés les fichiers en-têtes à inclure (en plus du répertoire courant) ;
-Lnom-de-répertoire : spécifie le répertoire dans lequel doivent être recherchées les librairies précompilées (en plus du répertoire usuel) ;
-o nom-de-fichier : spécifie le nom du fichier produit. Par défaut, le fichier exécutable fichier produit s'appelle « a.out ».
-O, -O1, -O2, -O3 : options d'optimisations. Sans ces options, le but du compilateur est de minimiser le coût de la compilation. En rajoutant l'une de ces options, le compilateur tente de réduire la taille du code exécutable et le temps d'exécution. Les options correspondent à différents niveaux d'optimisation : -O1 (similaire à -O) correspond à une faible optimisation, -O3 à l'optimisation maximale ;
-S : n'active que le préprocesseur et le compilateur ; produit un fichier assembleur ;
-v : imprime la liste des commandes exécutées par les différentes étapes de la compilation ;
-W : imprime des messages d'avertissement (warning) supplémentaires ;
-Wall : imprime tous les messages d'avertissement.
Les composants élémentaires du C
Un programme en langage C est constitué des six groupes de composants élémentaires suivants :
les identificateurs,
les mots-clefs,
les constantes,
les chaînes de caractères,
les opérateurs,
les signes de ponctuation.
On peut ajouter à ces six groupes les commentaires, qui sont enlevés par le préprocesseur.
Les identificateurs
Le rôle d'un identificateur est de donner un nom à une entité du programme. Plus précisément, un identificateur peut désigner :
un nom de variable ou de fonction,
un type défini par typedef, struct, union ou enum,
une étiquette (ou label).
Un identificateur est une suite de caractères parmi :
les lettres (minuscules ou majuscules, mais non accentuées),
les chiffres (sauf pour le premier caractère),
le « blanc souligné » ou « underscore » : « _ ».
! Le langage C est « case sensitive » (tient compte des majuscules/minuscules).
Exemples : var1, type_2 ou _deb sont des identificateurs valides.
Remarque : Il est déconseillé d'utiliser le underscore « _ » comme premier caractère d'un identificateur. En effet, par convention, il est souvent employé pour définir les variables globales de l'environnement C (prédéfinies par le compilateur).
Si la norme n’impose rien, pour éviter des surprises avec certains compilateurs, il est conseillé d’éviter de créer des identificateurs de plus de 31 caractères.
Les mots-clefs
Un certain nombre de mots, appelés mots-clefs, sont réservés pour le langage lui-même et ne peuvent pas être utilisés comme identificateurs. L'ANSI C compte 32 mots clefs :
autobreakcasecharconstcontinuedefaultdodoubleelseenumexternfloatforgotoifintlongregisterreturnshortsignedsizeofstaticstructswitchtypedefunionunsignedvoidvolatilewhileque l'on peut ranger en catégories :
les spécificateurs de stockage : auto, register, static, extern, typedef ;
les spécificateurs de type : char, double, enum, float, int, long, short, signed, struct, union, unsigned, void ;
les qualificateurs de type : const, volatile ;
les instructions de contrôle : break, case, continue, default, do, else, for, goto, if, switch, while ;
divers : return, sizeof.
Les commentaires
Un commentaire débute par /* et se termine par */. Par exemple :
/* Ceci est un commentaire */
On ne peut pas imbriquer des commentaires. Les compilateurs acceptent de plus en plus souvent les commentaires à la façon C++ : le commentaire commence par un double « / », et se continue jusqu’à la fin de la ligne. Exemple :
Ceci n’est pas un commentaire ; // Ceci est un commentaire
Structure d'un programme C
Une expression est une suite de composants élémentaires syntaxiquement correcte, par exemple :
x = y + 4
ou bien
(i >= 0) && (i < 10) || (p[i] != 0)
Une instruction est une expression suivie d'un point-virgule. Le point-virgule est donc le « séparateur d’instruction » ; il signifie en quelque sorte « évaluer cette expression ».
Plusieurs instructions peuvent être rassemblées par des accolades { et } pour former une instruction composée ou bloc qui est syntaxiquement équivalent à une instruction (le « { » signifie « début de bloc », ou « begin » dans d’autres langages comme le Pascal), et « } » signifie « fin de bloc » - le « end » - dans certains langages). Par exemple :
if (x != 0)
{
z = y / x;
t = y % x;
}
Une instruction composée d'un spécificateur de type et d’un identificateur ou d'une liste d'identificateurs séparés par une virgule est une déclaration. Par exemple :
int a;
int b = 1, c;
double x = 2.38e4;
La déclaration d’un tableau se fait avec les accolades. Exemple :
int b[10] ;
/* déclare un tableau b de 10 entiers. Le premier élément du tableau sera b[0], et le 10ième et dernier sera b[9] */
Remarque : en C, nous ne pouvons définir que des tableaux de taille connue lors de la compilation. Par exemple, le code suivant est interdit :
int a=f() ; /* la variable a est initialisée avec le résultat de l’appel à la fonction f() */
int b[a] ; /* à la compilation, la valeur de « a » est in