View
5
Download
0
Category
Preview:
Citation preview
OlivierEngler
etWallaceWang
ProgrammerpourlesNuls3eéditionTitredel’éditionoriginale:BeginningProgrammingForDummies
PourlesNulsestunemarquedéposéedeWileyPublishing,Inc.ForDummiesestunemarquedéposéedeWileyPublishing,Inc.
CollectiondirigéeparJean-PierreCanoTraduction:OlivierEnglerMiseenpage:MarieHousseau
EditionfrançaisepubliéeenaccordavecWileyPublishing,Inc.©ÉditionsFirst,undépartementd’Édi8,2017ÉditionsFirst,undépartementd’Édi812avenued’Italie75013ParisTél.:0144160900Fax:0144160901E-mail:firstinfo@efirst.comWeb:www.editionsfirst.frISBN:978-2-412-02576-5ISBNnumérique:9782412029572Dépôtlégal:2etrimestre2017Cetteœuvreestprotégéepar ledroitd’auteuretstrictementréservéeà l’usageprivéduclient.Toutereproductionoudiffusionauprofitdetiers,àtitregratuitouonéreux,detoutoupartiedecetteœuvreeststrictement interditeetconstitueunecontrefaçonprévuepar lesarticlesL335-2etsuivantsduCodede lapropriété intellectuelle.L’éditeurseréserve ledroitdepoursuivretouteatteinteàsesdroitsdepropriétéintellectuelledevantlesjuridictionscivilesoupénales.
CelivrenumériqueaétéconvertiinitialementauformatEPUBparIsakowww.isako.comàpartirdel'éditionpapierdumêmeouvrage.
P
Introduction
rogrammer ? Tout le monde a entendu parler de cette activité mystérieuse quiconsisteàcréerdeslogiciels.Celivrevousproposededécouvrircettesciencedefaçondifférentedeslivresetdessitesactuelsquiexpliquentlaprogrammation.
On peut être un très bon chauffeur de poids-lourd sans connaître la théorie desmoteursDiesel,maistouslespilotesdeligneconnaissentendétaillefonctionnementdechacundeséquipementsquiconstituentl'objetdanslequelilssontassis.
Programmer, c'est guider une machine d'un état à un autre au-dessus d'un océanhostile-lesbogues-,engarantissantlasécuritédespassagers-utilisateurs.
Pourqui,celivre?Ce livre ne présuppose aucune connaissance ni expérience en programmation. Leslecteursquivoudrontpratiquerlesexemplesaurontunminimumdesavoir-faireavecunordinateur(démarreruneapplication,trouverunfichier,naviguersurleweb,etc.),maisvouspouvezquasimenttoutliresanspratiquer.
En termesd'âge, savoir lire et se concentrerpour certaines sections sont les seulesconditions.
Lelivrevousaideranotammentdanslescassuivants:
» Vousêtescollégienoulycéenetvoudriezvérifierquevousavez
bienfaitdevousengagerdanscettedisciplineoudevousen
écarter.
» Vousêtesparentetvoulezaidervotreenfantàchoisirson
orientation.
» Vousêtessenioretaimeriezfairevospremierspasen
programmation.
» Vousêtescurieuxdesavoirdansquelétatd'espritestplongéeune
personnequiécritunprogramme.
» Vousavezuneidéed'applicationetaimeriezrevoirlesbasesavant
devouslancerdanslaréalisation.Enlittérature,quelleestla
proportiondelecteursparrapportauxauteurs?Celivreaaussi
commeobjectifdevousrendrecapabledelireetdecomprendre,
aumoinslesgrandeslignes,den'importequelprogramme,même
si,enfindecompte,vousnecomptezpas«vousymettre».
Demandezleprogramme!D'oùvientlemot«programme»?
«Pro»signifieversl'extérieur,verslaplacepublique.
«Gramme»vientdegraphein,noterparécrit, rendre tangible,communicableplustard,permanent.
Lapremièreutilisationdumot«programme»estmusicale.C'estundocumentdestinéà une diffusion publique annonçant ce que des artistes ont prévu de jouer lors d'unfuturconcert.Lalectureduprogrammepermetdoncdedéciderd'acheteroupasdesplaces.C'estunelisteprévisionnelled'actionssouhaitéesdansuncertainordrepouratteindreunobjectif(unbonconcert).
Au sens informatique, programmer c'est aussi préméditer des actions futures. C'estdéciderdeschangementsd'étatd'unautomateàpartird'unétat initialdéfini.Cequecet automatemodifie sont des représentations de choses vraies (ou fausses ! ) quiconcernentvotrepropreexistence,votrecompteenbanque,vosdonnéesdesanté,vossouvenirs,mêmeceuxquevousavezoubliésdepuis.
Oncomparesouventlaprogrammationàlacréationd'unerecettedecuisine,maisunerecette ressemble plutôt à un algorithme, et programmer, ce n'est pas que desalgorithmes. Un algorithme est une technique de résolution d'un problème qui s'estavéréeplusefficacequed'autres.Decefait,elleestdevenuegénérique.Pourréussirun clafoutis, il suffit de suivre la recette. Mais en programmation, vous devrezinventerleclafitouxetleclifoutat.
CommeledisaitlenomdugroupeanglaisSoftMachine,programmerc'estcréerunemachinemolle.
PréfacedeladeuxièmeéditionDepuislaparutiondelapremièreéditiondecelivre,l'engouementpourladécouvertedesprincipesdel'informatiquen'acessédecroîtrechezlesjuniorscommechezlesseniors.
Nousavonsdoncprofitédecettenouvelleparutionpourappliquerquelquesretouchesetvérifierquetoutcequiyestditresteàjour.
StructuredulivreCe livre comporte cinq parties : une importante partie centrale flanquée de deuxpartiesdepréparationetdeuxpartiesd'application.
La première partie vous propose de faire le lien avec votre quotidien. Nous yverronsquelaprogrammationestmoinséloignéedevousquevouspourriezlepenser.LeChapitre2donnel'occasiond'unpremierprojetdeprogrammationsansécrireunelignedecode.
Ladeuxièmepartieabordelanaissancedesmachinesàpenserentermesmatérieletintellectuel:automates,transistors,comptageenbasedeuxetporteslogiques.
La troisième partie s'étend sur huit chapitres pour découvrir pas à pas les grandsprincipesdel'artdeprogrammer:valeurs,variables,instructions,fonctions,tableaux,structures, construction de l'exécutable et librairies.Arrivé à la fin de cette partie,vousserezcapabledecomprendrelesgrandeslignesden'importequelinfolangageetdechoisird'enapprendreplusparailleurssicelavousamisenappétit.
Laquatrième partie profite de la précédente pour oser aborder des pratiques deprogrammation plus complexes : une application pilotée par événement sousWindows, les bases de la programmation orientée objets et une incursion dans lacréationdepageswebenHTMLavecCSSetJavaScript.
Lacinquièmepartieestconstituéedestraditionnels«Dixcommandements».Vousytrouverezdixpistespourallerplusloinetdixerreursdeprogrammationàéviter.
Une annexe est consacrée à l'installation d'un atelier de développement(Code::Blocks)etuneautrecontientlatabledescodesASCIIdescaractèresanglais.
L'approcheDansl'espritdelacollection«PourlesNul(le)s»,lelivreserebellecontrelafaçontraditionnelledeparlerdeprogrammation.C'est-à-dire?
Tous les livres et cours d'initiation (et l'auteur en a lu et francisé plus d'unecinquantaine) choisissent de commencer par un programme complet maisapparemmenttrèscourt:l'affichagedumessagedebienvenue«Helloworld».
L'intention est bonne, mais le lecteur est brutalement sommé de deviner en mêmetempsquasimenttouslesconceptsfondamentauxdelaprogrammation!Pourquoidesguillemets?Pourquoiprintf(),et#include,etcesaccoladespartout?Etcescaractèresdumessage,l'ordinateurlescomprend?Deplus,l'affichaged'unmessageàl'écranestloindeconstitueruneactivitécentraleenprogrammation.
Lespremièresphrasesque l'on apprendà écrire à l'écoleprimairene sontpasdesextraitsdeZolaoud'unrapportduFMI,mêmetrèscourt.Encomparaisondufrançais,un infolangage est beaucoup plus simple. Il suffit de commencer par lecommencement!
Unartdeprogrammer?L'ordinateur que vous alimentez avec un logiciel va faire exactement ce que leprogrammecontient.Cecidit,séparerainsilematérieldulogicielestréducteur,toutcommevouloirséparerlecorpsdel'âme.
Un ordinateur éteint (donc sans logiciel) est l'objet le plus inutile qui puisses'imaginer. L'ordinateur n'existe qu'une fois qu'un logiciel l'anime. Le logiciel estl'expressiond'unesortedescénarioquevousavezentièrementconçuenfonctiondel'idéequevousvousfaitesdufonctionnementdelamachine.
En quelque sorte, lorsque le programme fonctionne, il n'est que la preuve que lescénario développé dans votre esprit était limpide. C'est exactement comme untableau de peinture : s'il en émane assez de force pour toucher d'autres personnes,c'est que l'auteur a vécu une expérience intérieure forte au point de lui dicter lesmouvementsdesonpinceau.
LapratiqueNe vous basez pas seulement sur la pratique pour apprendre à programmer. Larédaction d'un programme est d'abord un processus mental. Il faut se rendredisponible.Programmer,c'estd'abordconstruirel'idéedecequel'onvaécrire,puispasseràl'écrituredansunsecondtemps.
Aussiimportant,sinonplus,quel'écrituredecode,ilyalalecturedestextessourcesécritsparlesautres!GrâceaumouvementdeslogicielslibresetOpenSource,vousdisposez dès le départ d'une fabuleuse bibliothèque. Lisez du code, cherchez àcomprendrecommentlesmeilleursprogrammeursonttrouvéleurssolutions.
Unbonécrivainouunboncompositeurontd'abord«fait leursclasses»enpuisantdanslesavoir-fairedeleursprédécesseurs.Undesobjectifsdecelivreestdevousaideràapprendreàlirelecodesourceplusencorequ'àl'écrire.Vosidéesdecréationviendrontd'elles-mêmesensuite.
Contrairement aux livres habituels pour débutants qui optent pour un langage«facile» (VisualBasic,Python),nousparlonsde langageCetmêmed'assembleur.Maisceslangagessontconsidérésde«basniveau».
L'expression « de bas niveau » possède cette connotation élitiste que l'on retrouvechezles«intellectuels»(ausenspéjoratif)quiveulentnierlecorps,alorsquec'estdesémotionsducorpsqueseconstruit l'âme,commel'ontmontré leschercheursenneurosciencescommeAntonioDamasio.
PourquoiavoirchoisileC?
1. LelangageCestbeaucoupplustransparentqueleslangages
de«hautniveau»quandils'agitdemontrerlescontraintes
qu'imposelematérielsurlesconditionsdecréation.
2. Enprésentantquelquesconceptsfondamentauxdefaçontrès
détailléecommenousleproposonsdanslaPartie3,ilest
ensuitebeaucoupplusfaciledemaîtrisern'importequelautre
langage.Vousenferezl'essaidanslaPartie4enabordant
(brièvementcarlaplacemanque)laprogrammationpilotéepar
événementsetlaprogrammationobjets.
Lesfichiersarchivesdesexemples
Lestroisièmeetquatrièmepartiescontiennentdenombreuxexemplesdetextesource.Il estbien sûr intéressantde les tester etde lesmodifierpourvoir cequi sepasseréellement.
Danslespremierschapitres,cesontdesextraitsnondirectementcompilables.Ilssontd'aborddestinésàêtrelus.Nousindiquonscependantaudébutdelatroisièmepartiecommentajouterunhabillagepermettantderendrecesexemplesopérationnels.
Voustrouverezlesexemplessousformedefichiersarchivescompresséssurlapagedulivresurlesitedel'éditeur:
www.pourlesnuls.fr
En bas de la page, choisissez téléchargement, puis dans la liste déroulante quiapparaît,choisissezPourlesnulsVienumérique.Cherchezlacouverturedecelivreetcliquez.Lalistedesarchivesvousestproposée.
Des conseils pour mettre en place les fichiers et les outils sont fournis avec lesarchives.
ConventionstypographiquesLesmots-clésdulangageCetlesnomsdesfonctionsprédéfiniessontimprimésdansunepolicefixe,commedansprintf()oubreak.
Les noms de fichiers et de dossiers sont imprimés en police sans serif en italique,commedansprogramme.exe.
Lesnomsdes commandesdans lesmenus sont imprimés sans serifgras : ouvrez lemenuFichier.
Leslistingssourcesontnumérotésdanschaquechapitre,commececi:
LISTING1.1:Exempledetextesource.
#include<stdio.h>
intmain(){
return(0);
}
Lalargeurlimitéedespagesimpriméesobligeàlimiterlalongueurdeslignesdetextesource.
IcônesutiliséesCette icône attire l’attention sur une information qu’il est important de mémoriser.Bienquejeconseilledetoutmémoriser,ils’agiticidequelquechosed’absolumentindispensable.
Uneastuceestunesuggestion,unetechniquespécialeouquelquechosedeparticulierquivousaideàêtreencoreplusefficace.
Cette icônemarque un piège à éviter, une information qui peut avoir de fâcheusesconséquencessivousn’entenezpascompte.
Bien sûr, tout est technique en programmation, mais je réserve cette icône auxcompléments,apartésetanecdotesencoreplustechniques.Considérez-lescommedesbonuspourultra-geeks.
RemerciementsL'auteurremercieparticulièrementJean-PierreCanodeluiavoirfaitconfiancepource titre qui constitue le point d'entrée pour tous les autres livres de la collection«PourlesNuls»consacrésauxlangagesinformatiques.
MercidufondducoeuràMartine,EvaetDéreckpouravoirsupportémavienocturneaulongdetouscesmois.
Un grand merci à l'éminent linguiste Richard Carter pour les discussions sur lesrapportsentreinfolangagesetlangageshumains.
AvertissementEnprogrammation,onprendrapidement l'habitudedetraquer lamoindrefaute,chezsoicommechezlesautres.Larigueurdesinfolangagesacetterigiditépourcorollaire.Certains professionnels de l'informatique seront donc prompts à relever des choixéditoriauxquilesauraientdéroutés.
Nous avons par exemple choisi de ne présenter la fonction d'affichageprintf()qu'au bout d'une centaine de pages, parce qu'elle suppose de maîtriser plusieursnotionsplusélémentairesd'abord.
Demême,nousavonschoisidenepasconsacrerbeaucoupdepagesàlaprésentationdetouteslesfonctionsprédéfiniesdulangage.Eneffet,unefoisquevousavezacquisdes bases solides, découvrir comment utiliser ces fonctions est aisé : il suffit depuiserdansladocumentationderéférence.
Denosjours,unprogrammeurpassebeaucoupdetempsàcréerdespasserellesentredesblocsfonctionnelspréexistants,blocsqu'ildoitapprendreàutiliser.Ilestdevenutrès rare de commencer un projet avec un écran vierge. Si après avoir lu ce livre,vousdécidezd'allerplusloinenprogrammation,prévoyezdoncdenejamaiscesserd'apprendre.
Gardonslecontact!Uneimportantenouveautédecetteéditionestlamiseàdispositiond'uneadressedecontact.Vouspouvezdorénavantnous transmettredes suggestionspour laprochaineéditionetposerdesquestions.
Pour bien utiliser cette opportunité, vous voudrez bien tenir compte des règlessuivantes.
Commencez le texte de l'objet dumessage (son titre) par la référence PROGPLN,commececi:
PROGPLN:Résumédemaquestion/suggestion
Envoyezvotremessageàcetteadresse:
firstinfo@efirst.com
Ayezunpeudepatience,carilfautquelquesjourspourretransmettrelesmessagesàl'auteuretluilaisserletempsderépondre.
Envoussouhaitantunagréablevoyagedansl'universdelaprogrammation!
IPremierscontacts
DANSCETTEPARTIE:
Untableurpourprogrammer?
LespagesWebvuesdescoulisses
L'atelierScratch
Unjeudetennisen30minutes
D
Chapitre1Lecodeestpartout
DANSCECHAPITRE:
» Formuler,c'estprogrammer
» Unefourmilièresouslecapot
ans bien des domaines d'activités humaines, les frontières entre l'intime etl'étrangersontfloues.Toutlemondeprogrammesajournée,sesprochainscongésetsesjoursdefête.Vousdirezquecen'estpaslamêmechose.Enapparence,oui.
Auquotidien,certainesactivitésconsidéréescommebanalesavecunordinateursontdéjàdesinvitationsàadopterl'étatd'espritduprogrammeur.Lemeilleurexempleestlelogicielbureautiquenommétableur.
VotretableurestprogrammableLe premier logiciel pour grand public qui permettait d'une certaine façon deprogrammer est un tableur, l'ancêtre de tous les tableurs : VisiCalc. Conçu fin1978parDanBricklinetBobFrankston,ilaengendréunedescendancequiaenvahilesbureauxetlesfoyersdumondeentier.
Quasiment quatre décennies plus tard, l'idée de génie de VisiCalc est toujours lefondement des tableurs modernes tels que Excel, LibreOffice et OpenOffice. Elleconsisteàpermettred'écriredansunecelluledetableaunonseulementunnombreoudutexte,maisaussiuneformule.Autrementdit,danslemêmeemplacement,ilpeutyavoirdesdonnéesouducodequigénèredesdonnées.
FIGURE1.1:VisiCalc,lepremiertableur.
Prenons un tableur moderne (OpenOffice). L'exemple suivant cherche à trouverautomatiquement le prix le plus bas pour une série d'articles dans les deuxsupermarchés lesplusproches.Nousavons saisiunéchantillondedonnéesetdeuxfoislamêmeformulesimplepourfairelasommed'unecolonne.
FIGURE1.2:Unefeuilledecalculavecdeuxformules.
DanslacolonneB,aulieudesaisirunevaleur,nousindiquonslaformule:
=SOMME(B4:B9)
Denombreuxlecteursconnaissentcettetechnique.Elleestremarquableparcequ'unefoisdéshabilléeelleesttrèssimilaireàcelle-ci:
ADDAdresse1,Adresse2
qui est typiquement du langage assembleur, directement compréhensible par unprocesseur.Nousyreviendronsdanslasuitedulivre.
Un tableur permet aussi des formules conditionnelles grâce à la fonction SI quiproposedéjàune syntaxe trèsprochedes instructions conditionnelles.Saisissons laformulesuivanteencelluleD4:
=SI(B4>C4;"Lanville";"Boucy")
Laformuledit:«Silavaleurdel'adresse(delacellule)B4estsupérieureàcelledel'adresseC4,nousinjectonslenomdusecondmagasin(lemoinscher)danslacellulecontenantcetteformule,etlenomdupremiersinon».
Nousprofitonsde l'excellentepossibilitédecopierelativepourremplir lacolonne.Nousajoutonsune formulesimilaire (=SI(D4="Lanville";C4;B4) )danslacolonnesuivante.
FIGURE1.3:Résultatsdesformulesaffichés.
Pourvoirlesformulesaulieudesdonnées:
» dansOpenouLibreOffice,ouvrezlaboîteOutils/Optionset
activezdansLibreOfficeCalc/Affichagel'optionFormules.
» dansExcel,dansFichier/Options,Optionsavancées,descendez
jusqu'àlacatégorieOptionsd'affichagedelafeuillepouractiver
l'optionFormulesdanslescellules.
Sansmêmeparlerdesmacrosdontsontdotés tous les logicielsbureautiquesdenosjours, un premier contact avec certains concepts de programmation est doncaccessibleàchacundenous.
Voyons maintenant un autre contexte où l'activité de programmation est trèsaccessible:votrenavigateurWeb.
LafourmilièresouslecapotLa navigation sur Internet (le Web) est devenue un acte quotidien. C'est aussi unmoyentrèssimplededécouvriràquoiressembleunprogramme.
Ouvronsparexempleunesessiondenavigationavecunnavigateurstandard,quecesoit Firefox,Chrome, Internet Explorer ou Safari (ou d'autres sousLinux).Voici lapaged'accueildusitedel'éditeurdecelivre:
FIGURE1.4:Lapaged'accueildusiteeditionsfirst.fr.
Prenezquelquesinstantspourrepérerlessectionsquiconstituentlapage:
» plusieursboutons-lienstoutenhaut;
» unebannièregraphique;
» unmenuhorizontalproposantdescatégories;
» unbandeauderecherche;
» puisplusieurssectionsdecontenu.
Etmaintenant,nouspouvonsbasculerd'ungestedanslescoulisses.Letableausuivantindiquequelestcegesteselonlenavigateur.
Tableau1.1:Accèsaucodesourced'unepageWeb.
Logiciel Technique
Firefox MenuOutils/DéveloppementWebetCodesourcedelapage.
Internet
Explorer
MenuAffichage/Source.
Safari 1)MenuSafari/Préférences,pageAvancées,optionAfficherlemenu
Développement.2)MenuDéveloppement/Afficherlecodesource.
Chrome MenuOutils,Afficherlasource.
LeraccourciclavierCtrl-UfonctionnedanstouslesnavigateurssousWindows(Alt-Pomme-UsousMac).Voicilerésultataffiché.
FIGURE1.5:Lecodesourcedelamêmepage.
Ce que vous voyez est du code source. Dans ce cas précis, c'est un mélange deplusieurslangages:
» duHTML:lesbalisesHTMLcommencenttoujoursaprèsun
chevrongauche;
» duJavaScript:toutcequisuitunmarqueur<scriptlanguage=...et
jusqu'auprochainmarqueurdefin</script>oubienlesliens
soulignésseterminantpar.js;
» duCSS:pourcontrôlerl'apparencevisuelledelapage;
» duPHP:pourgérerlecasoùlevisiteuraoubliésonmotdepasse.
Voiciledétaild'unfichierJavaScriptcontenudanslamêmepage.Vousconstatezqueles lignes ont des retraits variables à gauche (pour améliorer la compréhension ducode).
FIGURE1.6:ExtraitdecodesourceJavaScript.
Pour l'instant, tout ceci ne devrait pas vous parler,mais une fois les fondamentauxprésentés,ceserabienplusclair.
Notezquevouspouvez faireunecopie localede lapagecomplète (menuFichier/Enregistrersous)etvoirtouslesfichierssourcedanslesous-dossiercréé.
Aprèscepremiercontact,procédonsàuneséancecomplètedeprogrammation,maisavecunoutilvisuel.Iln'yaurapasuneligneàécrireetaucunlogicielàinstaller.EnroutepourScratch!
S
Chapitre2Uneséancedeprogrammationludique
DANSCECHAPITRE:
» L'atelierScratch
» Premierspas
» Unjeudetennissansécrireuneligne
cratchestlenomd'unlogicieldeprogrammationvisuelleconçuparunlaboratoirede recherche américain (le groupeLifelongKindergartenGroup) duMITMediaLabauMassachussets.Lelogicielestgratuitetsefondesurdenombreuxlogiciels
libres.
Depuis2012,Scratchestutilisable sans installation,dansune fenêtredenavigateurWeb.Plusde septmillionsdeprojetsontétéconçusenScratch,et leursauteursnesontpasquedesenfantsoudesadolescents.
EntrezdanslemondedeScratchOuvrezvotrenavigateurWebetcherchezàaccéderausitedulangageScratch.Voicil'adresseexacte:
scratch.mit.edu
FIGURE2.1:Lapaged'accueildeScratch.
Lapagedevraitêtreenfrançais.Ducôtégauche,repérezlagrandeicôneESSAIELE(ouTRYIT).Cliquez-la.Vousarrivezdans lafenêtred'expérimentation,c'est-à-direl'atelierdecréation.
Parfois, il y a trop demonde sur le serveur et certaines images ne s'affichent pas.Maislelienresteaccessibleauformattexte(Figure2.1).
Préparationdel'atelierAvantd'endécouvrirleséléments,faisonsleménage.NoussupposonsquevousavezcliquéESSAIE-LEouTRYIT.
1. Enhautàgauche,àcôtédutitreScratch,vousvoyezunpetit
globeterrestre.C'estunmenudanslequelvouspouvezchoisir
votrelangued'interface.Silesmenusnesontpasenfrançais,
choisissezFrançaisdanslaliste(Figure2.2).
FIGURE2.2:Débutdumenudeslanguesdel'atelierScratch.
2. SivousvoyezàdroiteunvoletGettingsstartedinScratchou
PriseenmaindeScratch,cliquezdanslacroixdefermeturedu
voletdanssonanglesupérieurgauche(Figure2.3).
FIGURE2.3:Boutondefermetureduvoletdroitduguide.
L'atelierestmaintenantdanssonétatinitial.
FIGURE2.4:Vuegénéraledel'atelierScratch.
Chatalors!Àgauchesouslemenu,vousvoyezunevastezoneblanche.CetespaceestlaScène.Ellecontientungrosmatouorange,lamascottedeScratch.DanslemondedeScratch,cetobjetvisuelsenommeunlutin.
1. Déplacezlepointeurdesourisdanslascènetoutenregardant
changersescoordonnéessouslascèneàdroite.Vous
comprenezquel'originedescoordonnéesestaucentredela
scène(justeàgauchedelaboucheduchat).
Lescoordonnéesaugmententversladroiteetverslehaut.Les
limitessontlessuivantes:
· danslesenshorizontal,de-240surlebordgaucheà+240sur
leborddroit;
· danslesensvertical,de+180surlebordsupérieurà-180sur
lebordinférieur;
C'estdanscetespacequenousallonsproposerunepromenadeau
matouenutilisantlesblocsd'actionduvoletcentral.
2. Danslevoletenbasàgauche,cliquezunefoisdansl'objet
visuelSprite1(notrematou)pourlesélectionner.
Ici,iln'yaqu'unobjetmaisilyaaussil'arrière-planScène,etc'estle
matouquenousvoulonsfairebouger.
3. Danslevoletcentral,cherchezleblocbleu(catégorie
Mouvement)suivant:
Avancerde10pixels
4. Cliquezetmaintenezleblocpuisfaites-leglisserjusqu'auvolet
droitetrelâchezàpeuprèsenhaut(laissezl'espacededeux
blocsau-dessus).
FIGURE2.5:Associationd'uneactionauchat.
Vousvenezdedéfiniruneinstruction.
5. Repérezledrapeauvertau-dessusdelascène.Ilsertà
démarrerleprogramme.Cliquez.Ilnesepasserien!
C'estnormal.Uneactionestassociéeàl'objet,maisriennedit
quandcetteactiondoitsedéclencher.Ilmanqueunévénement.
6. Danslevoletdesblocs,changezdecatégorieencliquantsur
Evénements.Vousvoyezdesblocsbruns.
7. RepérezleblocQuand(DrapeauVert)pressé.Amenez-ledans
levoletd'écriturededroiteau-dessusdel'autresansrelâcher.
Attendezdevoirlasilhouettedublocapparaître.Celaconfirme
quelenouveaublocserabienancréavantl'autre.Relâchez.
Silesdeuxblocsnesontpasenclenchés,déplacezl'unoul'autre
pouryparvenir.
FIGURE2.6:Ajoutd'unévénementdéclencheurdel'action.
8. Essayonsànouveauenutilisantleboutonvertdelascène.
Cettefois-cilechatsedéplaceunpeuversladroiteàchaque
clic,jusqu'àpresquedisparaîtredanslescoulisses.
FIGURE2.7:L'objetchatapresquedisparuàdroite.
(Vouspouvezl'agripperparlaqueuepourleramenerverslemilieu
delascèneouailleurs.)
9. Cliquezdanslazonenumériquedublocd'actionAvancerde…
etindiquezlavaleur50(pixels).Vousaurezmoinsàcliquer
pouratteindrelebord.
10.Danslevoletdesblocs,affichezlacatégorieMouvementet
repérezleblocTourner(VersLaDroite)de15degréssousle
dernier(bienancré).
11.Déposezceblocsousledernierenveillantàcequ'ils'accroche
sousl'autremouvement.
12.ToujoursdanslacatégorieMouvement,utilisezl'ascenseur
pourvoirleblocnomméRebondirsilebordestatteint.
13.Déposezceblocenl'accrochantauprécédent.Nousavonscréé
uneactionconditionnelle.
14.Essayezleprogramme.Lorsquelechattoucheassezlebord
droit,iltournesurlui-mêmeetrepartdansunautresens,et
ainsidesuite.
FIGURE2.8:Leprogrammequidonneuncomportementauchat.
En répétant le programme, vous remarquez que notre chat s'amuse comme un fou àfairedescabrioles.Maisledoigtsefatigueviteàcliquer.
UnmouvementpermanentPourquelechatsedéplaceseul,nousallonsajouterunebouclederépétition.Nousabrégeonslapromenadeavecleboutonrouged'arrêtimpératif.
1. Danslevoletdesblocs,affichezlacatégoriejauneContrôleet
repérezleblocRépéterindéfiniment.
2. Ici,ilfautêtredélicat.Danslebloc,cliquezàpeuprèssurle
débutdesalégende(Répéter…)etamenezleblocau-dessus
destroisblocsd'actionbleus.
Bougezlégèrementjusqu'àvoirlenouveaublocs'étendreen
hauteurpourengloberlestroisactionsaveclasilhouetteentrele
blocdedépartetledeuxième.Vouspouvezalorsrelâcher.
3. Lancezleprogramme.Selonladernièrepositiondel'objet,le
chatvafairedescerclesoubienrebondir.
4. Utilisezleboutonrouged'arrêt.
Vouspouvezentredeuxessaisfairevarierlesparamètres:la
quantitéd'avanceenpixelsetl'anglederotation.Vousverrezquesi
lechatn'avancepasassez,ilvatournerenrondcarjamaisplusil
n'avanceraassezpourtoucherunbordetdoncrebondir(cequifait
changerdesens).Vouspouvezarrêterleprogrammeetplacerle
chatplusprèsd'unbordavantderelancer.
Notrepremierprogrammeestterminé.Sivousvoulezpouvoirleretrouver,ilvousfautlestockerenlieusûr,parexemplesurledisquedevotreordinateur.
FIGURE2.9:Ajoutd'unebouclederépétitioninfinie.
Sauvonslechatfou1. OuvrezlemenuFichierenhautàgaucheetchoisissezla
troisièmecommande,Téléchargerdansvotreordinateur.
DonnezparexemplelenomChatfouetvalidez.
FIGURE2.10:SauvegardeduprojetChatfou.
2. Vouspourrezretrouvervotreprojetplustardavecladeuxième
commande(Importerdepuisvotreordinateur).
L'atelier Scratch permet donc de découvrir les principes de la programmation sansdevoir apprendreàécriredansun infolangage.Passonsàunprojetplusconséquentpourdécouvrird'autresconcepts.
Créationd'unjeuenScratchNousallonssupprimerlematou!Serions-nouscruels?Nullement.Vouscomprendrezpourquoi il vautmieux ne pas nous servir dumatou pour le projet que nous allonscréer,carnousrisquerionsuneplaintedelaSPA.
1. DanslemenuFichier,choisissezNouveau(New).Sivousne
venezpasdesauvegarder,uneboîtevousdemandesivousacceptez
d'abandonnertoutcequiaétéfaitjusque-là(lemessageestpeut-
êtreenanglais:Discardcontents...?).Dansvosfuturessessionsavec
cetoutil,faitesunepauseàcemomentavantd'accepter.En
informatique,onpeutperdrequatreheuresdetravailenune
microseconde.
Vousvoyezl'interfaceinitialedeScratch:
· àgauche,deuxpanneauxsuperposéspourlaScèneetlaboîte
àobjets;
· aucentre,lepanneaudesblocsd'actionsetd'instructions;il
montreaudépartlesblocsdelacatégorieMouvement;
· àdroite,lepanneauderédactiondesprogrammes,vide
puisquerienn'aétéécrit.
2. Amenezlepointeurdesourissurlegrosmatou(passa
vignetteenbas)etcliquez-droitpourouvrirlepetitmenulocal.
FIGURE2.11:Lemenulocald'unobjet.
3. ChoisissezlacommandeSupprimer.
Lematoudisparaîtdelascène,maisenoutrelevoletcentralsevide
detouslesblocsbleus.Cen'estrien.Ilsvontréapparaîtrequand
nousauronsànouveauaumoinsunlutin.
Sur certaines machines, le menu local n'apparaît pas à cause d'un souci dans laversion deFlash.Dans ce cas, sélectionnez le chat dans le voletLutins en bas àgauche,puisouvrezlapageCostumesaumilieuenhautetsupprimezmanuellementleouleschatsavecleboutonEffacerduvoletdroit.
Réfléchiravantd'agirLe jeu que nous allons créer est une sorte d'entraînement de tennis. Comme nousutilisonslelangageScratch,leprojets'appelleraScrannis.
Avantdenousjeterdanslaréalisation,ilnousfautétudiercedontnousavonsbesoinetquelscomportementsdevrontavoirnosobjets.Ilnousfaut:
» uneballe;
» uneraquette;
» troismursrebondissants;
» unmurabsorbantsouslaraquette.
Auniveaudescomportements:
» laballedoitpartirdumurdufondetrebondirsurtroismursavec
unanglesipossiblechangeant;
» surlemurderrièrelejoueurlaballedoitêtrehappéeetentraînerla
findelapartie;
» laraquettedoitpouvoirêtredéplacéedanslesenshorizontalpour
renvoyerlaballeparrebond.
Commençonsparlaballe.
FIGURE2.12:Schémadeconceptionduprojet.
DessinonsunpremierobjetDansScratch,vousdisposezd'unebibliothèqued'objets standard.Dufaitqu'ilnousfautuneballe,nousallonslacréerrapidementavecl'outildedessinintégréàl'atelier.
1. LepanneauinférieurgauchedesLutins(sprites)possèdesa
proprebarred'outils.Repérezceluireprésentantunpinceauet
cliquezpourbasculerdansl'éditeurgraphique.
FIGURE2.13:Boutondecréationd'unobjetgraphiquedansl'éditeur.
D'office,unnouvelobjetapparaîtdanscemêmepanneau,avecun
nomprovisoireSprite1.Lapartiedroitedelafenêtreaccueille
l'éditeur.C'estdanscetéditeurquenousallonsmaintenant
travailler.
2. Dansl'éditeurgraphique,sélectionnezlaquatrièmeicône,
Ellipse.Cliquezetmaintenezenglissantpuisrelâchezpour
dessinerunpetitcercle.
LecercleseraparfaitsivousmaintenezlatoucheMajtouten
traçant.
3. Poursupprimerunessai,cliquezpourfaireapparaîtreles
poignéesdecoinetappuyezsurlatoucheSuppr.
Faitesensortequelecerclesoitmoinsgrandquelahauteurdedeux
boutonsàgauche(voyezlafiguresuivante).Audépart,c'estun
cerclevideentraitnoir.
4. Sélectionnezl'outilPotdepeinture(Rempliravecdela
couleur)puiscliquezdansungodetdecouleurenbas(lesballes
detennissontsouventjaunes).Cliquezensuiteàl'intérieurde
laballepourlacolorier.
Vousnepouvezpasdéplacerl'objetdansl'éditeur.Aucune
importance,vouspourrezledéplacersurlaScène.
5. Danslehautdel'éditeur,vousremarquezunezonedesaisie
quicontientunnomprovisoire(costume1).Cliquezdansce
champ,sélectionnezletexteetsaisissezlemotballe.Cesera
lenomdecetteapparencedelaballe(uneapparenceest
appeléeuncostumedansScratch).
FIGURE2.14:Laballecrééedansl'éditeur.
6. Laballeestprête.Revenezenmoded'affichagenormalgrâceà
l'ongletScriptsenhautdupanneaucentral.
Vousretrouvezlesblocsbleuscommepromispuisqu'ilexiste
maintenantaumoinsunobjet.
Si maintenant la connexion au serveur de Scratch est rompue, vous perdez tout letravail effectué.Parmesuredeprécaution, avantd'aller plus loin, créonsun fichierlocalduprojetdanssonétatd'avancementactuel.
Sauverlesmeubles(etlesballes)1. OuvrezlemenuFichier(celuideScratch,pasdunavigateur!)
etchoisissezTéléchargerdansvotreordinateur(versvotre
ordinateurseraitplusadapté).
Eneffet,pourlemoment,votreprojetn'existequesurunemachine
situéeonnesaitoùsurleterritoiredesÉtats-Unis.
Vousvoyezapparaîtrelaboîtededésignationdefichierstandardsur
votremachine.
2. Saisissezlenomscrannis01.
Parfois,ilfautpréciserl'extensionsb2quiestparfoisoubliée.
Vousvoiciàl'abridesintempériesduWeb.
MettrelaballeenmouvementNousvoulonsquelaballesedéplace,nitropvite,nitroplentement.DansScratch,ilsuffit de la faire avancer par étapes d'un certain nombre de pixels. De plus, nousvoulonsqu'ellefassedemi-tourquandlaballetoucheunbord.Scratchprédéfinitunefonctionpourdétectercelaetréagirenconséquence.
1. DanslaScèneàgauche,ilyalaballe.Aveclasouris,déplacez-
laenobservantl'évolutiondescoordonnéesàdroitesousle
panneau.
2. Déposezlaballeenhautaucentre,àpeuprèsaux
coordonnéesx=0y=150.
3. Danslepanneaudesblocs,ouvrezlacatégorieEvénementset
déposezleblocQuand(DrapeauVert)pressédanslepanneau
derédactionàdroite.
Onveutquelaballesedéplacesansjamaiss'arrêter,sauflorsqu'ellesortduterrainducôtédelaraquette.Nousallonsdoncmettreenplaceunebouclederépétition.
4. AffichezlesblocsdelacatégorieContrôleetdéposezunblocà
fourcheRépéterindéfinimentsouslepremierblocdupanneau
droit.
5. AffichezlesblocsdelacatégorieMouvementetdéposezun
blocdedéplacementAvancerde10pixelssousledernierbloc
dupanneaudroit.
Lerésultatdoitressembleràlafiguresuivante.
6. Pourjugerdurésultat,démarrezleprogrammegrâceau
bouton(DrapeauVert)au-dessusdelaScène.
Laballevaversladroitepuiss'arrêteavantdedisparaître.
7. Enfait,leprogrammefonctionnetoujours!Aveclasouris,
ramenezlaballesurlagaucheetrelâchez.Ellerepartsurla
droite.
8. Utilisezleboutonrouged'arrêt.
C'est un bon début. La balle n'arrête de se déplacer que parce que le langage labloquepourqu'ellenesortepasentièrementduchampdevision.Voyonscommentlafairerebondir!
FIGURE2.15:Codeinitialdelaballe.
DétecterunefrontièreScratch sait que ses futurs utilisateurs vont souvent créer des jeux. Une fonctionspécialeaétéprévuepourdétecterquandunobjettoucheunbord.
1. ToujoursdanslesblocsdelacatégorieMouvement,faites
défilerpourrepérerleblocdedétectionRebondirsilebordest
atteintquiesttoutenfindeliste.Déposezceblocsouslebloc
bleudupanneaudroit.
Soyezattentif:leblocnedoitpasêtreancrésouslabranchedela
bouclejaune,maisvenirs'insérerdanslaboucleenseconde
position.
FIGURE2.16:Lescriptdelaballeaprèsajoutdelafonctionderebond.
2. Testezlescript.Laballerebonditbien,maissansdouteaprès
unchangementdecoordonnéesimprévu.C'estliéaufaitquele
centredegravitédel'objetnecoïncidepasavecsoncentre
visuel.
3. Rebasculezdansl'éditeurd'objetencliquantdansl'onglet
Costumes.
Enhautàdroite,vousvoyezungroupedetroisboutonssanstexte.
Cliquezsurledernier(Définirlecentreducostume).Unpointeurà
réticuleapparaît.
4. Cliquezbienaucentredelaballepouryplacerleréticule.
FIGURE2.17:Réglageducentredegravitédelaballe.
5. Rebasculezenmodescriptetlancezleprogramme.
S'ilresteunpetitdécalagelorsduchangementdesens,cen'estpas
grave.Vouspouvezfairedesessaisdevitesse:
1. Arrêtezlescript.
2. DansleblocAvancerdexxpixelsduscriptàdroite,cliquez
danslavaleuretindiquezparexemple50puis100,puis10en
redémarrantàchaquefois.Trouvezunevitesseraisonnable.
Surunemachinerécente,unevaleursupérieureà20varendrelejeu
difficile.Toutdépenddelapuissancedelavôtre.
Nousavançons,maislatrajectoiren'estvraimentpasintéressante.Rendons-lamoinsprévisibleetplusréaliste.
ContrôlerlatrajectoireNousallonsfairevarierl'orientationinitialedelaballegrâceàunblocquifaitpartied'unecatégoriequenousn'avonspasencorerencontrée.
1. DanslesblocsdelacatégorieMouvement,repérezunbloc
intituléS'orientersuivantunangledeoubienS'orienterà.
Insérezceblocavantlabouclederépétition,soitjustesousle
premierblocdedémarrage.
2. AccédezauxblocsvertsdelacatégorieOpérateurs.Insérezun
blocNombrealéatoireentre1et10dansleréceptaclepour
l'angledublocprécédent.
Laballedenotreexempleestronde,maisellepossèdemalgrétout
uneorientation,c'est-à-direl'angledesatrajectoirefuture.Les
coordonnéessontétabliesainsi:
0overslebas,90oversladroite,
180overslehautet270overslagauche.
FIGURE2.18:Ajoutd'uneorientationinitialechangeante.
3. Spécifiezunevasteplagedevaleursaléatoires:indiquez
Entre1et360.
Admirezlerésultat.Repositionnezlaballeavantchaquerelancepour
bienvoirqueladirectioninitialechangedefaçonimprévue.Les
mouvementssuivantssontlerésultatdesrebonds.Ilssontmoins
imprévisibles.
Procédezàunesauvegarded'étapedansunfichiernomméscrannis02.
CreuserlefonddecourtPourquelejeuaitdel'intérêt,ilfautqu'undesquatremurssoitouvert,ensortequesilaraquettemanquelaballe,celle-cisoitperdue,etlapartieaussi.
Nousallonsdoncintervenirsurlemurdubas,làoùviendraseplacerlaraquette.
Comment faire ? Scratch propose une fonction qui détecte lorsqu'un objet entre encontact avec une surface d'une certaine couleur (que les autres objets ne possèdentpas).Ilsuffitdoncdedessinerunrubanparexemplerougecontrelebordinférieuretdefairedétecterlacollisionentrelaballeetlacouleurdecefonddecourt.
Nousn'allonspascréerunnouvelobjetmaismodifierlefonddescène(arrière-plan).
1. Enbasàgauche,cliquezdanslazoneScène1arrière-planpuis
basculezenmodeéditionvial'ongletArrière-plansaucentreen
haut.
2. Danslebasdupanneaud'édition,cliquezdanslegodetde
couleurdetraitpuisdanslegodetdecouleurrouge(le
quatrièmesouslenoir).
Nousallonsdessinerunrectanglerougeenbas.
3. Sélectionnezl'outilRectangle.
L'opérationsuivanteestunpeudélicateparcequeleslimitesdetracénesontpasbienvisibles.Vérifiezquelafenêtreestassezgrandeenlargeurpourqu'iln'yaitpasdebarrededéfilementhorizontale sous lazonede travail.Sinécessaire, augmentez lalargeurdefenêtrepourquecettebarredisparaisse.
4. Amenezlepointeurdesourisàmi-cheminentreladernière
icônedesoutilsetlazonedechoixdecouleurpuisfaitesglisser
enremontantenbiais.
Lebutestd'obtenirunrectangletrèsallongé(toutelalargeurdu
bord).Aidez-vousdelafigure2.19.
FIGURE2.19:Créationd'unfonddecourtrouge.
VouspouvezrecommenceràzérogrâceauboutonEffacerduhaut.
Unefoislerectangletracé,s'ilestvide,ilresteàlerempliravecle
mêmerouge.
5. Sélectionnezl'outilPotdepeinture(Rempliravecdela
couleur),cliquezdanslegodetrougepuiscliquezdansle
rectanglepourlepeindre.
6. Silerectangleesttropoupasassezépais,servez-vousdel'outil
Sélectionner(justeau-dessusdutampon).Zonezautourdu
rectanglepourfaireapparaîtrelespoignéespuistirezversle
hautoulebas.
7. Revenezaupanneaudesscriptsenutilisantl'ongletenhautau
centre.
Détecterlacollisionballe/murrougeLemurderrièrelejoueurréclameuncomportementspécialdelaballe.Riennenousempêchededéfinirunsecondblocdansunobjet.
1. Activezl'objetSprite1danslepanneaudesobjetsàgaucheet
cliquez-droitpourchoisirInfo.
2. Profitons-enpourdonnerunnomappropriéàl'objet:Balle.
(Unobjetpeutposséderplusieurscostumesafindechanger
d'aspectencoursdeprogramme.)
3. Danslevoletdeconstructionduscriptàdroite,déposezun
blocdedémarrageQuand(DrapeauVert)pressé(catégorie
Evénements)bienàl'écartdupremierensemble,endessous.
4. AccédezàlacatégorieContrôle.CherchezleblocAttendre
jusqu'à__.Accrochez-lesousleprécédent.Ledétecteurde
couleurestdansunenouvellecatégorie.
5. AccédezàlacatégorieCapteurs.CherchezleblocCouleurX
touchée.Insérez-ledanslelosangerécepteurdublocd'attente.
6. Cliquezdanslegodetdecesous-bloc.Lepointeurdevientune
pipettedecopiedecouleur.DanslepanneauScène,cliquez
danslabarrerouge.
FIGURE2.20:Scriptdedétectiondecollisionaveclemurdefond.
Vousêtesainsiassuréqueceseracettecouleurquiservirade
déclencheur.Legodetdelaconditiondoitprendrelamêmecouleur.
7. Ajoutonsuneactiontemporairepourtesternotrenouveau
script.DanslacatégorieApparence,prenezunblocDireHello
pendant2secondesetaccrochez-lesousleprécédent.
Testonsnotregroupededeuxscriptsdeballe.Dèsquelaballetouchelemurdubas,lemessageapparaîtetlaballerebondit.Notezquelemessageneréapparaîtpluslorsdesprochainscontacts.Eneffet,nousn'avonspaseubesoindeplacercesblocsdansunebouclepuisqu'àtermececontactdoitprovoquerl'arrêtduprogramme.
FIGURE2.21:Laballedétectebiensoncontactaveclemur.
SupprimerunblocNousn'avonsplusbesoindublocdemessage.
1. Cliquez-droitdedansetchoisissezSupprimer.Letourestjoué.
2. AccédezàlacatégorieContrôle.CherchezlepetitblocStop
tout.Accrochez-leàlaplacedeceluiquevousvenezde
supprimer.
Dorénavant,sivoustestez,laballesefigeaucontactdumur.Gameover!C'estlebut.
Ilresteunsouci.Lorsquevousrelancez,laballepatinesielleestencoreaucontactdelacouleurrouge.Ilfaudraitlaramenerenhautdescèneaprèschaquearrêt.
1. Agrippezlaballedanslascèneetramenez-laaumilieuen
haut.
2. OuvrezlacatégorieMouvement.CherchezleblocAlleràx:_y:_
etinsérez-leentrelepremieretledeuxièmeblocdunouveau
script(doncavantAttendre…).
3. Sivousavezremontél'objetavant,lescoordonnéesdevaient
êtrequasimentcorrectes.Retouchezs'illefautpourquex
indique0ety150.
FIGURE2.22:Lescriptdefindejeuterminé.
Maisjouerautennis,c'estplusintéressantavecuneraquette.Occupons-nousdecela.
CréationdelaraquetteNous allons créer un nouvel objet. Ce sera une raquette symbolique : un rectangleoblongquipourrasedéplaceruniquementdegaucheàdroiteenmêmetempsquelasouris.
1. Danslepanneaudesobjets,utilisez,commepourlaballe,
l'outilDessinerunnouveaulutin.L'éditeurgraphiquede
costumesapparaît.
2. Dansl'éditeur,activezl'outilRectanglepuissélectionnezle
noircommecouleurdetraitetderemplissage.
3. Aumilieudelasurface,dessinezunpetitrectangleplat.
Remplissez-le(pasenrouge!).C'esttout.
FIGURE2.23:L'objetgraphiqueraquette.
4. Positionnezlecentredegravitédel'objetcommedéjà
expliqué.
Si,plustard,voustrouvezquel'objetesttropoupasassezgros,
vouspourrezleretoucheravecl'outilSélectionner.
5. Quittezl'éditeuravecl'ongletScriptaucentre.DanslaScène,
repositionnezvotrenouvelleraquettepourqu'ellesoitàpeu
prèsaumilieuenbas,justeau-dessusdumurrouge.
6. Danslepanneaudesobjets,sélectionnezlaraquette,cliquez-
droitpourchoisirInfoetdonnez-luisonvrainom:Raquette.
Procédezàunesauvegarded'étapedansunfichiernomméscrannis03.
UneraquettequibougePour l'instant, la raquette est inerte et trouée. Voyons d'abord comment la faire sedéplacerenmêmetempsquelepointeurdesouris.
Lasolutionest simple :nousmettonsenplaceunebouclede répétition infiniedanslaquellenousrecopionslacoordonnéeenXdelasourisdanslacoordonnéeenXdelaraquette.
1. Voltigezd'unecatégoriedeblocsàl'autrecommevoussavezle
fairemaintenant.DéposezunblocdedémarrageQuand
(Drapeau)(Evènements)puisunblocRépéterindéfiniment
(Contrôle).
2. AccédezàlacatégorieMouvementetcherchezleblocDonner
lavaleur0àx.
3. AccédezàlacatégorieCapteursetcherchezleblocSourisx.
Insérez-ledansleréceptacledublocprécédent.
FIGURE2.24:Lescriptdelaraquette.
Vouspouvez tester leprojet.La raquette sedéplacebienavec la souris. Ilne restequ'unproblèmeenattente:laraquetteesttrouée!
UneraquettequirenvoielaballeSivous testez le jeu, vous constatezque la raquette, bienque solide en apparence,laissepasserlaballe.Unpetitscriptdansl'objetBalleet le trouseraréparé.Nousallonsdétecterlecontactetfairefairedemi-touràlaballe.
1. Activezl'objetBalle(non,pasl'objetRaquette)pourafficher
sesdeuxscripts.Prévoyezunpeudeplacedanslepanneaude
droitepourpouvoirajouterunscriptdesixblocs.
2. DéposezunblocdedémarrageQuanddrapeaupuisunbloc
Répéterindéfiniment.
3. EnrestantdanslacatégorieContrôle,repérezleblocdetestSi
__alors.Insérez-ledanslabouclederépétition.
4. AccédezàlacatégorieCapteursetinsérezlebloc__touché?
danslalignedetitredublocconditionnel,justeentrelemotsi
etlemotalors.
5. Laconditionn'estpasencoredéfinie.Siquoitouché?Ouvrezla
listedelaconditiontouché?.Touslesobjetsexistantssont
proposés,doncvoustrouvezRaquette(d'oùl'intérêtdebien
nommerlesobjets).SélectionnezRaquette.
6. OuvrezlacatégorieMouvementetdéposezdanslebloc
conditionnel(cettefois-ciàl'intérieurdesdeuxfourches)un
blocTournerdexxdegrés(parladroiteoulagauche,celane
changerarien).
7. Cliquezdanslavaleurnumériquedublocdedemi-touret
indiquez180.
FIGURE2.25:Letroisièmescriptdelaballe.
Silaballetouchelemuràtraverslaraquette,vousavezdeuxsolutions:soitremonterla raquette de quelques pixels, soit réduire un peu la hauteur du mur rouge pouraugmenterl'espaceentremuretraquette.
Testdelaversion1.0duprojetSitouts'estbienpassé,vousdisposezmaintenantd'unprogrammecomplet.
FIGURE2.26:VuedelaScènedujeuterminé.
Lasauvegarde!Profitez de cemoment de joie pour penser à créer une copie de sécurité de votreprojet sur votre ordinateur.Le site deScratch est très fréquenté. Parfois, il devientinaccessible.
1. DanslemenuFichier,choisissezTéléchargerdansvotre
ordinateur.
2. Danslaboîtededésignation,indiquezparexemplelenom
scrannisV1(extension.sb2sinécessaire)etvalidez.
Il est possible qu'il ne soit plus nécessaire d'indiquer l'extension .sb2quand vousferezcetexercice,siledéfautaétécorrigédepuis.
Enrouteverslaversion1.1
VotrepratiquedeScratchvousapeut-êtredonnédesidéespourenrichirceprojetouvouslancerdansunautre.
Ilyadeuxaméliorationsquenouspouvonsencorefaireensemble:
1. Ajouterl'affichagesousformedescoredunombredeballes
renvoyées.
2. Faireémettreunpetitsondeballeaumomentducontactavec
laraquette.
LeconceptdevariableNousn'avonspasencoreutilisélemotvariabledepuisledébutduchapitre.Pourtant,nous en avons utilisé environ une dizaine sans le décider explicitement : lescoordonnées,lesanglesderotation,lesmouvements,etc.
Voyonscommentdéfinirunevariablepuisl'afficheretfairevariersavaleur.
1. Activezl'objetBalleetsonpanneauScript.Accédezàla
catégoriedeblocsDonnées.
2. CliquezsurleboutonCréerunevariable.
3. Donnezàlavariableunjolinom,parexempleScore.
FIGURE2.27:Créationd'unevariable.
4. Nechangezpasl'optionPourtousleslutinsetvalidezparOk.
Immédiatement,laScènereçoitdanssonanglesupérieurgaucheunafficheurdunometdelavaleurdelavariable.Nouslelaisseronsàcetendroit.
IlfautquelavariableScorecomptelenombrederenvoisdeballesparlaraquette.Danslesblocsapparuspourlavariable,nousremarquonsceluinomméAjouteràScore1.Oùleplacer?
Il fautque le score augmentedans le script du contact entreballe et raquette.C'estceluicontenantletestSiRaquettetouché?alors.
1. DéposezleblocAjouteràScore1.danslescriptindiquésousle
blocdedemi-tourTourner__de180degréspourqu'ils'y
accroche.
2. Testezvotrecompteurdepoints.Vousallezremarquerun
dernierdétail.
FIGURE2.28:Instructiond'augmentationdevaleurdelavariable.
(Dans les figures, nous avonsparfois déplacéunpeu les autres scripts pour rendrel'affichagepluslisible.Ilsuffitdeprendrelescriptdésiréparsonpremierbloc.)
Ledernierproblèmeestquelescoren'estpasremisàzéro(réinitialisé)audébutdelapartiesuivante.DanslacatégorieDonnées,lavariableScorepossèdeunblocprévupourdéfinirlavaleurdelavariable(Mettre…).Dansquelscriptl'insérer?
Pourquoipasdansleblocdefindepartiecontenantletestdecontactaveclemurdufond?
1. VérifiezquevousêtesfaceaupanneaudeScriptsdelaballe.Si
nécessaire,accédezàlacatégorieDonnées.
2. DéposezleblocMettreScoreà0audébutduscriptcontenant
Attendrejusqu'àcouleurtouchée?justesousleblocde
démarrage.
FIGURE2.29:RemiseàzérodelavariableScore.
Testezlerésultat.Biensûr,puisquevousêteslecréateurdujeu,vouspouveztrichersurlescore:ilsuffitdechangerlavaleurinitialedansleblocMettreScoreà.
Une dernière retouche très simple va nous permettre de découvrir le monde dumultimédia.Nousallonsajouterunsonaucontactraquette/balle.Deuxétapessontàprévoir:
1. Définitiondunouveauson.
2. Ajoutd'unblocpourjouercesondanslebonscript.
Définitiond'unsonScratchestfourniavecunebibliothèquedesonsdebasequisuffiraànotrebonheur.
1. Activezl'objetBalleetbasculezdanssonpanneauSonsque
nousn'avonspasencorevisité.
2. Enhautàgauchedupanneau,choisissezlepremierbouton
représentantunhaut-parleur(Choisirunsondansla
bibliothèque).
Unegrandeboîteaveclessonsstandardapparaît.Sileserveurde
Scratchn'estpassurchargé,vouspouvezécouterlesautressons.
Pensezàcliquerànouveausurleboutondelecturepourarrêterle
son.
3. Descendezdanslalistejusqu'ausonpop.Sélectionnez-leet
validezparOk.
4. VousrevenezaupanneauSons.Lenouveausonpeutêtre
édité,maisnousallonsdirectementnousenservir.
5. RebasculezdanslepanneauScriptsdelaballe.
FIGURE2.30:Choixd'unsonstandard.
FIGURE2.31:Lesonajoutéauprojet.
FIGURE2.32:Ajoutd'unblocJouerleson.
6. LacatégoriedeblocsSonsdoitêtretoujoursaffichée.Insérez
leblocJouerlesonpopdanslescriptdelaraquettetouchée
justeaprèsleblocAjouteràScore1.
Vouspouvez tester leprojetdans saversion1.1.Pensezà faireune sauvegarde.Etsurtout,jouezunpeuetcorrigezlesimperfectionss'ilenreste.
TestengrandformatVousavezpeut-êtreremarquétoutenhautàgauchesousletitreScratchunrectangleentourédequatrecoinsetd'unnumérodeversion.C'estleboutondepassageengrandformat.Utilisez-lepourtesterleprojet.
Voiciquelquespistespourpoursuivre:
1. Silejeuesttropfacile,ilsuffitd'augmenterlepas
d'avancementdanslescriptprincipaldelaballe(celuiavecle
blocRebondir).
2. Vouscorsezlejeuenréduisantlediamètredelaballe.Activez
leboutonRéduiredanslabarredemenuenhautpuiscliquez
autantdefoisquenécessairesurlaballedanslaScène.
FIGURE2.33:Testduprojetengrandformat.
PourcontinueravecScratch,voyezlessitesenfrançaisscratchfr.free.fretmagicmakers.frainsiquelesitederéférencescratch.mit.edudéjàcité.
Qu'avons-nousdécouvert?Une séance Scratch se veut ludique afin d'attirer la curiosité à tout âge. Vousdécouvrez ainsi quelques grands principes de programmation : la répétition,l'exécutionconditionnelle,lesvariables,lesappelsdefonctions.
Leressentiestunpeulemêmequelorsquevousvenezdediscuteravecunepersonneenutilisantlesservicesd'uninterprète.Nivotreinterlocuteur,nivousn'avezéchangédirectement,quellesquesoientlesqualitésdel'interprète.
Pour pouvoir bien dialoguer, nous allons apprendre à penser nos programmes enfonctiondespossibilitésdel'ordinateur.Commençonspardécouvrircommentestnéecetteétonnantemachineuniverselle.
IILamachineàpenser
DANSCETTEPARTIE:
Lepresquevivant:lesmécanismes
Desnombresparouiounon
Deséclairsouvrentdesportesdanslesable
C
Chapitre3Desmachines…
DANSCECHAPITRE:
» Lepresquevivant:lesmachines
» Automatesetengrenagesetpetitstrous
» Calculsanalogiques
» Classifier,trier,ranger,nommer
» Relais,lampes,transistorsetpuces
oncevoirdesprogrammesinformatiques,voicibienuneactivité«moderne»pardéfinition,non?Pourtant,cen'estpasdehierquel'humainchercheettrouvedessolutionspourêtreplusefficace,moinspérissable,plusfort,plustranquille,plus
heureuxensomme.Nousprofitonsde5000ansd'optimisation.
Optimisationparl'outilTout d'abord, avec des outils. La pointe de silex, prothèse de la main pourmieuxcouperlaviande,puislapierreàlanceretlaflèchecommetransmetteursauprèsdeleurcibled'uneinformationvitale:«J'aifaimdetoi!»L'outilestuneextension,uneaugmentation,del'humain(laréalitéaugmentéeadoncquelquesmillénairesdéjà).
OptimisationparlamachinePendant son développement, l'enfant ne se concentre que sur l'essentiel. Chaqueapprentissageest liéàuneémotion.Dans lescontréesàneige, l'enfantqui fabriqueunegrosseboulepuislafaitdévalerunepentedevientobservateurd'uncomportementautonomedequelquechosequin'estpasvivant,maispourtantquiaunetrajectoire,undestin:allerd'unpointàl'autre.Biensûr,labouleroulesousl'effetdelagravitation,maisquilesaitàquatreans?
Ceconceptd'objetautonomedontlecomportementestprévisibleestenquelquesortel'embryondel'idéedemachine.
Machine: termedésignantquelquechosequirendpossible.Enproto-indo-européen«maghana » vient de «magha » , la capacité de faire.Unemachine augmente nospouvoirsnaturelsinnés.
LesmachinesmécaniquesDevenir dix ou cent fois plus fort sans médicaments ? Insérez entre la charge àdéplacer et la planète une roue qui va traduire la ligne droite du déplacement encercles, ce qui réduit les frottements. La roue est l'une des machines simples desGrecs,aveclelevier,lapoulieetlavis.
Lespremièresmachinesmécaniquesontserviàaugmenterlaforce.Ellesontd'abordétécrééesparinstinctdesurvie,poursedéfendre:cesontlesmachinesdeguerre.
D'autres machines ont servi à prévoir et à se diriger : ce sont les calculateursd'astronomieetleshorloges.Laclepsydreetlesablier,instrumentsapproximatifsdemesuredutemps,ontlaissélaplaceàundispositifbeaucoupplusfiableconstituéderouesdentées,l'horlogemécanique.
Vérifier le soir qu'il nemanque pas une bête à son troupeau reste faisable par unberger avec ses doigts demains et de pieds (jusqu'à quarante bêtes). En revanche,calculer une position astronomique (phases de la lune pour maîtriser le temps,navigation en haute mer) suppose des calculs répétitifs. L'humain a donc très tôtcherchéàsesimplifierlatâche.
Onaretrouvéen1900prèsdelaCrète,aufonddelaMéditerranée,unétrangerestede cadran métallique, la machine d'Anticythère. Constituée d'une trentained'engrenages, elle permet de prévoir les éclipses du Soleil et de la Lune. Elle estconsidéréecommeleplusanciencalculateurastronomique.
Parmi toutesces inventions techniques, l'engrenageadonc jouéun rôlemajeur.Unefois qu'une configuration de roues dentées est en place, il suffit de mettre lemécanisme enmouvement pour obtenir un comportement prévisible et constant.Lesrapports entre les roues dentées (nombre de dents des pignons) sont des rapportsarithmétiques.
CalculsanalogiquesC'estlogiquementavecdesengrenagesqu'ontétécrééeslespremièresmachinespoursoulagernonleseffortsphysiques,maisleseffortsintellectuelsdeshumains.Cesontlesmachinesàcalculer.
UnedespremièresestcellequeBlaisePascalacrééevers1650pouraidersonpèrecollecteur des impôts à faire ses comptes. On faisait tourner les roues de cettemachineàlamain,maisellesavaitdéjàpropagerlaretenue.
(©MUSÉEDESARTSETMÉTIERS)
FIGURE3.1:LaPascalinedeBlaisePascal.
AutomatesUn domaine voisin est celui des automates : de savants arrangements mécaniquesdotés d'un comportement défini. Le programme de l'automate est, comme pour laPascaline, figé dans le mécanisme. Dans les années 1740, le Grenoblois JacquesVaucansonavaitcrééunjoueurdeflûtegrandeurnatureetuncanardpuisamiscetteexpérienceàprofitpouraméliorerlesmétiersàtisser.
Les roues à picots et cylindres servaient aussi dès cette époque à faire jouer desboîtesàmusiqueetdesorguesmécaniques.
LetissudevéritéL'artdutissageestconnudepuislanuitdestemps.Croiserdesfilsàangledroitpourla chaîne et la trame représente un terrain propice à une certaine abstraction. NosécransLCDactuelssefondentsurlamêmestructureenlignesetcolonnes.
AudébutduXVIIIe siècle, leLyonnaisBasileBouchoncommenceà automatiser lemétier à tisser avec un ruban perforé que son assistant Falcon remplace par descartes.
En1800, Joseph Jacquardproduit une synthèsedes savoirsdeVaucansonet de sesdeuxcollègueslyonnaiseninventantlemétieràtisserdesmotifs.
Le principe trou/non trou du métier Jacquard préfigure le système binaire. Pourchangerdemotif(deprogramme),ilsuffisaitdechangerdejeudecartes.
(GEORGEP.LANDOW,VICTORIANWEB.ORG)
FIGURE3.2:UncartondumétierJacquard.
LemoteuranalytiquedeBabbageDanslesannées1830,l'AnglaisCharlesBabbageacommencéàconcevoirlathéoried'unemachinedecalculentirantprofitdesavancéestechniquesdesesprédécesseursfrançaisdansledomainedesautomates,notammentleconceptdecarteperforée.
Babbage a posé les bases de l'informatique actuelle. Sa machine basée sur desengrenages avait unepartie pour calculer (lemoulin) et unepartie pour stocker lesvaleurs.Troislecteursdecartesétaientprévus.
Cartesd'actionsLes cartes d'actions permettent les quatre opérations arithmétiques (addition,soustraction, multiplication et division). Des cartes spéciales marquées « C »permettent de revenir en arrière (lettreB) afin de répéter la lecture d'une série decartesd'actionsoudesauterplusieurscartesenavant(lettreF).Babbageavaitmêmeprévu le concept de test pour reculer ou avancer seulement si une conditiondéclenchéepar un levier est satisfaite.Lenombrede cartes à sauter est indiqué enquatrièmepositionsurlacarte.
CartesdevaleursconstantesLescartesdevaleursserventàindiquerdesvaleursnumériquesquisontconfiguréesdans la partiemémoire. Lorsque cettemémoire est pleine, des places peuvent êtrelibérées,quitteàrecharger lesmêmesvaleursaubesoinpardescartes.Lesvaleurssontengénérallesrésultatsdescalculsprécédents.Denosjours,celacorrespondauxvaleursnumériqueslittéralesquenousverronsdanslaPartie3.
Cartesd'entrées/sortiesdevariablesUne carte de lecture/écriture contient une adresse mémoire et indique le sens detravail,soitpourcopierlavaleurdepuislestockverslecalculateur(premièrelettreLpourLoad),soitpourrangerlerésultatdanslestock(premièrelettreSouZ).
Enlecturedepuislamémoire,deuxmodessontprévus:avec(lettreZ)ousans(lettreSpourStore)remiseàzérodel'adresseoùétaitstockéelavaleur.Aprèslalettresetrouveuneadresseentre000et999.
Souvenez-vousdecettedescriptionquandvousaurezfinilalecturedulivre.Pendantpresque un siècle, les choses n'ont plus beaucoup avancé. Les idées de Babbagerestent effectivement en vigueur dans les ordinateurs du début de ce nouveaumillénaire.
FIGURE3.3:PrototypedelamachineanalytiquedeBabbage.
Babbage n'avait pas eu le financement nécessaire pour construire sa machine àdifférences no2 dotée d'une sorte d'imprimante sans encre. Sa construction n'a étéréaliséequ'en2002àLondres.Ellefonctionnecommeprévu.
LaféeélectricitéDepuis la période de la Grèce antique, on connaissait l'électricité statique, cettedécharge que vous ressentez après avoir marché sur une moquette synthétique entouchantunepoignéedeporte.Maisellenefaisaitquepasseroutomberducieldansleséclairs.
Vers1750,onaréussiàenstockerunpeudansunebouteilleenverreentouréed'unefeuillemétallique(labouteilledeLeyde).Lecondensateurétaitné,unbarragepourstockerdel'énergieélectrique.
Classifier,trier,ranger,nommerHerman Hollerith (1860-1929) était employé du bureau du recensement des États-Unisdans lesannées1880.Leprochainrecensementétaitprévupour1890.L'affluxdepopulationd'Europefaisaitcraindrelepireauxemployésdubureau.Ilspensaient
qu'il leur faudrait huit ans aumoins pour centraliser les relevés des enquêteurs deretourduterrain.Hollerithcherchaitunmoyend'automatiserlerecensement.
Prenant le tramway un matin, il vit que le contrôleur poinçonnait les tickets pourmarquerlelieudemontéeetquelquesdétailsdécrivantleporteur(sexe,couleurdescheveux, etc.). Soudain, il s'est dit : « Il me faut le même système pour nosrecenseurs. » Hollerith combina les cartes de Jacquard aux récents progrès del'électromécanique(lescontactsàmercure).
Le premier support matériel de données était né : la carte perforée. La grandecontribution de Hollerith était son système de lecture des cartes. Les trouspermettaient lecontactentreune languetteet lemercuresous lacarte,cequi faisaitavancer un compteur à électro-aimant. Au départ, on pouvait compter 40 donnéesdifférentes(sexe,religion,profession,étatmarital,nombred'enfants,etc.).
Lerecensementde1890aétéachevéendeuxansaulieudehuit,etlesuccèsaattirélescompagniesdecheminsdeferpourgérerleursdonnéescomptablesetleshorairesdes trains.En1911, la société IBMaété fondée àpartir de cette technologie, puistous les secteurs d'activité ont progressivement adopté la mécanographie qui estdevenulesystèmedetraitementdedonnéesnumériquesjusquedanslesannées1960.Un demi-siècle de perforatrices, trieuses et tabulatrices. Un demi-siècle de relaisélectro-mécaniques.
FIGURE3.4:Unecarteperforéeavec80colonnes.
Lestubesàvides(«lampes»)AudébutduXXesiècle,l'électroniqueavanceàgrandspas.Dès1905,FlemingpuisDeForestmettentaupointladiode,unesortedelampequinelaissepasserlecourantélectrique que dans un sens, ce qui permettait de transformer du courant alternatif(plus facile à transporter) en courant continu (pour alimenter des appareils
électroniques).Ladiodeestamélioréesousformedetriode,quipermetd'amplifierunsignal faible. Le tube à vide est ainsi devenu le composant de base des premiersappareilsélectroniques(radar,radio,télévision,etc.).
Maisuncomposantélectroniquepeutaussiservirenimitationd'unrelais,c'est-à-direentout-ou-rien(lemode«commutation»).Danslesannées1930,onacommencéàutiliser des tubes en remplacement des relais pour les calculateurs grâce à deuxénormes avantages : il n'y a pas d'effet de rebond au contact puisqu'il n'y a pluscontactetl'étatpeutêtreinversé(ouvert/fermé)environmillefoisplusvite.
Pouranimeruncalculateur,ilfautdesmilliersdetubesquiconsommenténormémentd'énergie.Leslimitesallaientêtrerapidementatteintes.Lecoûtd'unemachinebaséesur les tubesne laissaitsûrementpas imaginerquel'onauraitbesoindemillionsdeprogrammeursquelquesdécenniesplustard.
Lessemi-conducteurs(transistors)Vers la finduXIXesiècle,ondécouvrequecertainscristaux(notamment lagalène,sulfuredeplomb)conduisentmieuxl'électricitédansunsensquedansl'autre.Ilssontsemi-conducteurs.Lecristaldegalèneestàl'originedeladiffusionparondesradio.Mais il faudra attendre encore un demi-siècle pour que l'on maîtrise assezprécisémentl'ajoutde0,001%d'unautreélément(antimoine,arsenic,bore,gallium)dansdugermaniumoudusiliciumpourledoper(lerendreuntoutpetitpeunégatifoupositifpuiscollerunepartienégativecontreunepositive,cequidonneunejonctionquinelaissepasserlecourantquedansunsens).
En effet, peu après la fin de la SecondeGuerre se produit une vraie avancée : onparvientàproduiredefaçonfiabledesmatériauxsemi-conducteursàbasedesilicium(tirédusabledequartz).Letransistor,trèspeugourmandenénergie,trèspeucoûteuxàproduireetencoreplusrapidequeletube,allaitdonnernaissanceàl'informatiquepourtous.
Vers1960,onacommencéàregrouper(intégrer)destransistorssurunmêmemorceaude silicium de la taille d'un ongle. D'abord des dizaines, puis des centaines, desmilliersetdesmillionsdetransistorsdeplusenpluspetits,organisésencouches.
Denosjours,surlasurfaced'untimbre,oncréeunréseauinterconnectédeplusd'unmilliarddetransistors.C'estuncircuitintégré.Unboîtierrectangulaireoucarréavecdenombreusespetitesbrochesavecàl'intérieurunepetiteplaquedesiliciumappelée«puce».
FIGURE3.5:Uncircuitintégréélectronique.
Biensûr,cetteintégrationn'estpossiblequeparcequechaquetransistorneconsommeque très peu d'énergie. Mais on est arrivé à des dimensions proches de la limitematérielle,avecdesépaisseursdematièredequelquesdizainesd'atomes.
Pourquoi«puce»?Parcequelemorceaudesiliciumesttrèspetit.LesAnglaisontchoisichip,maisd'ungenrequines'avalepas(pasencore?).
Etensuite?Tout est prêt pour plonger dans l'aventure de l'informatique à vaste échelle. Tout ?Cecin'estque lapartiematérielle.Voyonscomment ilaétépossibled'insufflerunecertaineformed'intelligencedanscesgrainsdesable.Placeauxmathématiciens.
Q
Chapitre4...etdesnombres
DANSCECHAPITRE:
» Onrentreàlabase
» Calculsbinairesetbitfiches
» Valeursnégativesetàvirgule
» L'hexadécimal
uedesunsetdeszéros?
L'interrupteur électronique est une belle invention, mais elle ne suffit pas à faireécloreleprincipedel'ordinateur.Unseconddomainedeconnaissancess'estcombinéà cet interrupteur : la représentation de nombres uniquement avec deux chiffres :le0etle1.
Non, les mathématiques en base 2 ne sont pas indignes de l'honnête homme. Unerapidevisitedesesrouagespourramêmedonnerunnouveléclairagesurcequinoussembleàtousévident:comptersursesdoigts.
Jour!Nuit!Traiterquelqu'undebinaireestpéjoratif.Celaqualifieunepersonnequimanquedenuanceentredeuxextrêmes.Pourtant,l'exclusionentredeuxétatsestfondamental:
» C'estlejouretlanuit!
» C'estouiouc'estnon?
» Blancounoir.
C'est à partir de deux que tout devient possible, puisqu'il y a une différence. Lareprésentationbinaireestpossibleparcequ'onadécouvertquel'onpouvaitfairetouslescalculsdansuneautrebasequelabasedixdenotreenfance.
Allô,labase?IcilecomteArbourVoussavezcomptez?Sansdoute,maislaplupartdesgensnesaventcompterquedanslabase10,labasedécimale.
Lavaleurdécimalehabituelle145sedécomposeainsi:
145=1×100+4×10+5×1=100+40+5
Nousavonstellementpratiquécettebasequ'ilnousestdevenuquasimentimpossibled'yréfléchir,unpeucommesivousdeviezanalyserlentementchacundevosmusclespendantquevousmarchez.
Pourtant,cettebasedécimalen'estpasaussinaturellequelamarchepourvotrecorps.LesMayasetlesAztèquescomptaientenbase20.Vousêtes-vousdemandépourquoion disait encore quatre-vingts et pas octante ? C'est une trace d'une ancienneutilisationdelabase20enGaule.
Revoyonslafaçondontnouscomptonsjusqu'à10:
1,2,3,4,5,6,7,8,9et10.
Chiffres et nombres : Les chiffres, ce sont les dessins graphiques que nousinscrivonset reconnaissons. Ilyena9plus lezéro.Ecrire10n'est pas écrire unchiffre,c'estécrireunnombreconstituédedeuxchiffres.C'estunedizaineseulementlorsquenouscomptonsenbase10.
Petitvoyageenquintalie(base5)Décidons de compter en base 5. Dans ce cas, nous ne pouvons utiliser que cinqsymboles(cinqchiffres).Aulieud'eninventer,prenonsledébutdeceuxdusystèmedécimal,donc0,1,2,3et4.
Commentécrireenbase5lavaleurdécimale12?
Base10Correspondanceenbase5
11
22
33
44
5??
Il n'y a pas de chiffre en base 5 pour cette valeur, donc nous entamons la 1re«cinquaine»surdoncdeuxchiffresquisontle1etle0:
510
611
712
813
914
10??
Nous sommes au bout de la 2e série de cinq, doncmême principe avec un 2 pourdébuterla2ecinquaine:
1020
1121
1222,fini!
Donc, la valeur décimale 12 s'écrit 22 en base 5. Pour le vérifier, faisons laconversioninverse.Enbase5,22correspondà:
» 2cinquainescomplèteset2unités.
» 2cinquainesvalent2x5soit10,+2fontbien12.
Pour compter en base 5, on se sert des puissances de 5. Nous allons maintenantcomptercommelesordinateursenbase2,etdoncdécouvrirlespuissancesde2.
LesShadoksontutilisélabase4(leschiffres0,1,2et3).BobyLapointeautilisélesbases4et16.Iladonnédesnomsàseschiffresde0à15:HO,HA,HE,HI,BO,BA,BE,BI,KO,KA,KE,KI,DO,DA,DE,DI.19décimalseditHAHI.
LepouvoirdespuissancesdedeuxLapluspetitebasepossibleestlabasedeux.Comparéeàtouteslesautres,commelabase cinq qui nous a servi d'apéritif, la base deux est beaucoup plus simple, tropsimplepourdeshumains.
Au sortir duMoyen-Âge, onn'imaginait pas que les recherches desmathématicienspourraientunjourserviràcréerlascienceinformatique.Saluonscesprécurseursquiontétudiélanumérotationdansplusieursbasesautresquelabasedécimale,dontbien
sûr la base deux : lesAnglais ThomasHarriot, Francis Bacon et JohannNeper auXVIIe,puisl'AllemandLeibniz(vers1680),cemêmeLeibnizdontlestravauxarrivésjusqu'enChine auraient rappelé auxAsiatiques que leurs ancêtres avaient étudié labasedeuxbienavantl'èrechrétienne.
Cette base deux est devenue le système unique de représentation des données eninformatique.Parnumérisation, toutcequinousimportedenosjours(images,sons,données personnelles, etc.) a été converti en base deux. S'intéresser à laprogrammationimpliquedeprendreunpeudetempspourcomprendrecommenttoutestcalculableavecsipeudechiffres.
Pourobtenir ledébutdelasériedespuissancesdedeux,oncommenceà1(commedanstouteslesbases)puisondoublelavaleurprécédente,cequidonne:
1,2,4,8,16,32,64,128,256,512,1024,2048,...
Chaquepuissancevacorrespondreàunepositiondechiffre,commedansnotrebasedix.Lespuissancesdedixs'égrènentainsipourcomparaison:
1,10,100,1000,10000,100000,1000000…
(DOMAINEPUBLIC)
FIGURE4.1:LepapyrusRhindégyptienutilisantdespuissancesdedeux.
FARAMINEUX,LESPHARAONS!
Onaretrouvésurdespapyrusvieuxde3500ansdesfragmentsde
multiplicationquiprouventquelesÉgyptiensaimaientdéjàprofiter
desavantagesdespuissancesde2.
Lesscribespréparaienttouteunesériedetablesàdeuxcolonnes:
les puissances de deux à gauche et en regard lesmultiples d'un
nombre. Ils trouvaient d'abord la plus grande puissance de deux
inférieure ou égale au nombre en question, la soustrayaient et
recommençaientl'opérationjusqu'àcequ'ilneresteplusrien.
Parexemple,pourmultiplier40par26(décimal!),ilsdressaientleur
table à deux colonnes avec les puissances deux à gauche et les
mutiples du plus grand des deux nombres (40) à droite puis
décomposaientl'autrenombreenpuissancesdedeux.
Attention : on travaille en commençant en bas et en remontant
dansletableau.
Il ne reste plus qu'à faire la somme des multiples marqués :
80+320+640=1040.
Puissances
de2
Multiples
de40
Raisonnement
1 40 Ilneresterienàchercher.
2 80 Danslereste2,ontrouve2,reste0.On
marque80.
4 160 2estpluspetitque4,onignore.
8 320 Danslereste10,ontrouve8,reste2.On
marque320.
16 640 Dans26,ontrouve16,reste10.Onmarque
640.
32 1280 26estpluspetitque32,onignore.
64 2560 26estpluspetitque64,onignore.
Calculonsenbase2Siuneminusculeplaquettedesablefondu(unprocesseur)saitcalculerenbase2dèssanaissance,unhumaindevraityarriver,non?
Labase2oubinaireLaplusradicaledessimplificationsconsisteànegarderquedeuxsymboles, le0etle1.Noustravaillonsdorénavantavecdes«deuzaines».
Comptonsjusqu'à12enbase2:
Base10Base2
00
11
2??
Déjàplusdesymboles,doncdébutdelapremière«deuzaine».Nousécrivonsdeuxchiffresquirestentle1etle0:
210
311
4??
Déjàplusdesymboles,doncdébutdelapremière«2-centaine»donctroischiffresquirestentle1etle0.Onreprend:
4100
5101
6110
7111
8???
Déjàplusdesymboles,doncdébutdupremier«2-millier»doncquatrechiffresquirestentle1etle0.Ontermine:
81000
91001
101010
111011
121100,fini!
Lavaleurdécimale12 s'écrit1100en binaire.Le premier 1 de gauche vaut 8 (2puissance3)etlesuivantvaut4(2puissance2),cequifait12.
Pour distinguer les valeurs en base 10, nous ajouterons un suffixe _d (un dminuscule),commedans5_d.Pourcellesenbase2,nousécrirons0_bou1_b.
ConstruisezvotrejeudebitfichesPourrendreladécouverteplusagréable,nousallonsnousdoterd'unjeudefichesenpapier.Lesopérationsdeviendrontainsitrèsconcrètes.
Chaque ficheva représenterphysiquementuneunitédecomptagebinaire,unchiffrebinaire(BInarydigiT,abrégéenbit).Dansunpremiertemps,nousallonsmanipulerdes valeurs naturelles, donc uniquement positives et entières (pas de signe, pas devirgule).
L'objectifdecebrefatelierdedécoupageestdedisposerd'aumoins16petitesfichesdemême taille et de deux petits objets non identiques (jetons de deux couleurs oupièces de monnaie différentes) qui serviront de retenues positive et négative. Lesfiches seront alignées côte à côte. Pour armer une fiche (faire passer son étatde 0 à 1), il suffira de la hausser d'à peu près une demi-hauteur de fiche parglissementavecundoigt.
Voicilesdeuxjeuxdebitfichesàconfectionner:
FIGURE4.2:Lekitdeseizebitfichesetdeuxjetonspourcompterenbase2.
1. PrenezunefeuilledepapierA4.Coupez-laendeuxdanslesens
delahauteur.Gardezunedemi-feuilleA5.
2. Posezlafeuilleàplat,lescôtéslongsdanslesenshorizontal.
Vousalleztraceraucrayonsurcettedemi-feuilleunquadrillageavec
unerègleetuncrayon.
3. Repérezàpartirduhautà5cmet10cmettracezdeuxtraits
horizontauxafindediviserlafeuilleentroisbandes.
(Celan'apasd'importancequelesfichesn'aientpasexactementla
mêmehauteur.)
4. Danslesensvertical,divisezlasurfaceensixpartiesen
traçantdesrepèresauxpointssuivantsetenpartantdela
gauche,puisentraçantsixlignesverticales:
3 ,5cm,7cm,10,5cm,14cmet17,5cm
5. Découpezles18fichesetgardez-en8.Posezlesautresplus
loin.Posezles8fichescôteàcôte.
6. Prenezungrosfeutreoumarqueuretnumérotezchacunedes
huitbitfichesavecdespuissancesde2décroissantes.
128 64 32 16 8 4 2 1
27 26 25 24 23 22 21 20
Inspirez-vousdelaFigure4.2pourécrireunnombreengrosdansla
partiesupérieureetunepuissancede2enpetitdanslebasdela
fiche.
7. Prenezhuitautresfichesdustocketnumérotez-les
exactementdelamêmefaçonpuisrangez-lesenréservepour
quandnousferonsdesadditions.
8. Nousauronsbesoind'uneretenuedèsledépart,puisd'une
retenuenégative.Trouvezdeuxjetonsdifférents(unnoiretun
rougeseraitidéal)oudeuxpiècesdemonnaiedifférentes.
Vousêtesprêt.Audépart,nousn'utilisonsqu'unjeudehuitfichesetlesdeuxjetons.
Installez-vousàune tableoùvousaurezassezdeplacepourposerquatre sériesdehuitbitfiches(mêmesivousn'enutiliserezquedeuxaumaximum).Gardez-vousdescourantsd'air.
Posez un seul jeu de huit bitfiches de gauche à droite en commençant par la plus« grande » (128) et en décroissant. La bitfiche du 1 doit être la dernière à droite(revoyezlaFigure4.2).
Comptezenbase2sansvousénerverChaquepositionbinaire,doncchaquefichenepeutreprésenterquedeuxvaleurs,zéroouun.Nouschoisissonsdelaisserlaficheenpositionbassepourzéroetdelafaireglisserd'unedemi-hauteurpourdirequ'elleestàun.
Les quelques exercices qui suivent vont vous permettre de vivre physiquement laréalité des valeurs qui circulent dans le circuit de calcul d'un ordinateur. Lesexercicesd'additionsontlesmêmesquecequisepassedansleprocesseur.
Exercice1:conversionverslabase2
Pour commencer, voici une valeur écrite en base 2.Nous avons bien huit chiffres,donchuitfiches.
01100011
Reproduisezcetteprésentation.Haussez(faitesglisserverslehaut)lesquatrefichesqui correspondent à des1 : celles desvaleurs 64, 32, 2 et 1.Les autres restent enpositionbasse.Ellesvalent0.
FIGURE4.3:Lavaleurdécimale99enfichesbinaires.
Pour trouver la valeur décimale, on additionne les valeurs des fiches haussées :64+32+2+1=99.
Il suffit de lire la position de vos fiches et de faire la somme. Faisons l'opérationinverse.
Pour rendre la valeur plus facile à lire, l'habitude consiste à espacer un peu pluschaquegroupedequatrebits:01100011.
Exercice2:conversiondepuislabase2Faites une remise à zéro de votre système : replacez toutes les fiches en positionbasse.Nouspartonsmaintenantdelavaleurdécimale154.Combienenbinaire?
CommelesÉgyptiens,nousdécomposons.Voyons,quelest laplusgrandepuissancededeuxinférieureàcenombre?128.
Onditaussiquec'est lebitdepoidsfort (MSB,Most SignificantBit). Le bit desunités(leplusàdroite)estlebitdepoidsfaible(LSB,Least…).
Nouspouvonsretrancher128aunombreàconvertir.154-128donne26.
1. Haussonslafichedu128.Ilreste26.
Poursuivons.Quelleestlapuissancededeuxquientredans26?
Ni64,ni32,mais16,oui.
2. Onhausselafichedu16etonretranche16.Reste10.Lafiche
du8estcandidate.
3. Onhausselafichedu8.Ilreste2,valeurquiconvientà
merveilleàlafichedu2.
4. Onhausselafichedu2.Ilneresterienàdistribuer.
Vousdevezavoirhausséquatrefiches,niplus,nimoins.Lisonslerésultat:
10011010
FIGURE4.4:Lavaleurdécimale154enfichesbinaires.
Vérifions.Onadditionnelesvaleursdécimalesdesficheshaussées:
1fois128
+0fois64
+0fois32
+1fois16
+1fois8
+0fois4
+1fois2
+0fois1
============
154
Le compte est bon !Ne touchez pas les fiches ; elles vont servir pour le prochainexercice.
OCTET-VOUSDELÀ!
Cen'estpasparhasardquenoustravaillonsavechuitfiches.C'estlepaquetde
huitchiffresbinairesquiestdevenul'unitéstandarddanslesordinateurs.C'est
lapluspetitequantitéqu'unordinateurpeutmanipuler(hormisdesexceptions
trèstechniques).Cepaquetsenommeunoctet(lesoctopodesonthuitpattes),
enanglaisunbyte.
Exercice3:ajoutde1enbase2Nousallonsavoirbesoindenotrepionderetenue.
Si vous avez effacé le dernier nombre, repositionnez-le.Maintenant, vous savez lefaireavecpourseulindicececi:10011010.
Nous allons ajouter1 à lavaleur.Trop facile, onhausse la fichedu1.Recomptez.Voustrouvezbien155décimal?
FIGURE4.5:Lavaleurdécimale155parajoutde1.
Nousensommeslà:10011011.
Préparezvotrejeton(maisn'ayezpaspeur).Nousallonsessayerd'ajouterencore1àlavaleuractuelle.Maisnoussommesbienembêtés.Lafichedu1estdéjàhaussée!
Avant de poursuivre, voici la table de vérité pour savoir comment additionner desnombresbinaires.Leprincipeesttrèssimple:1+1=10.
Tableau4.1:Tableaudevéritédel'additionbinaire.
EntréeA EntréeB Sortie Retenue
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0(avec1enretenue) 1
Vousvoyezdansladernièrelignedelatableque1+1donne10,lenouveau1étantuneretenueàajouteraubitdegauche.
1. Posezlejetonderetenueau-dessusdu1.Enbinaire,
1+1font10,puisquelesunitésreviennentà0etoncommence
une«deuzaine».
2. Nouspouvonsdoncbaisserlafichedu1etfaireglisserlejeton
deretenued'uncranverslagauche,au-dessusdelafichedu2.
Mince,lafichedu2esthausséeaussi.Mêmeprincipe:10+1...stop!Laretenueareçu de la promotion. Elle vaut deux fois plus depuis que nous l'avons fait glisserd'uneficheverslagauche!Ellevautdonc10enbinaire.Houlala.10+10enbinaire,qu'est-cequecelapeutfaire?
Neregardezquelesdeuxficheslesplusàdroite(oubliezlaretenueuninstant).Pourl'instant,lafiche2hausséeetla1baisséereprésentent10,donc2endécimal(2_d).Donc,logiquement2_dfois2_dfont4_d.Cen'estpasparcequec'estbinairequecelachange les règles (heureusement pour nos carnets de notes et feuilles de paieinformatisés).
Lavaleur4?Ellenoustendlesbras:latroisièmefiche!Voyons…
Ouf,ellen'estpashaussée.C'estavecplaisirque:
1. Nousbaissonslafiche2.
2. Nousglissonslaretenued'uncranàgauche(décaléedeuxfois,
ellevautmaintenantdeuxpuissance2,soit4).
Cela tombe bien. La fiche 4 s'ennuyait. On lui propose de représenter la valeurdécimale 4 ? Elle peut le faire, elle va le faire, c'est d'ailleurs tout ce qu'elle saitfaire.
3. Haussezlafiche4etenvoyezlaretenuedansuncoin,loindes
fiches.
Aufait,oùensommes-nous?
10011100
FIGURE4.6:Enfin,noussommesà156,etsansretenue.
Exercice4:additionenbase2Voyonsmaintenantcommentadditionnerdeuxvaleursbinairesdemême taille.Cetteopérationestphysiquementréaliséepar lescircuitsdel'ordinateurencombinant lesétatsélectriquesdedeuxgroupesdexfilsquidécidentdel'étatélectriquedexfilsdesortie.Nousyreviendronsdansleprochainchapitre.
Voyonscommentadditionner6+5décimal,donc0110+0101:
0110//2fois2+2fois1=6
0101//2fois2+1fois1=5
---------
1011
Prenezlesecondjeudebitfiches.Pouréviterd'aligneruntroisièmejeudefichespourle résultat, nous réutilisons le jeu du bas pour la somme.Nous lisons dans le sensverticalencommençantparlerang1,doncdedroiteàgauche.
1. Premierrang:0+1=1.Netouchezàrien.
2. Deuxièmerang:1+0=1.Baissezlaficheduhautethaussez
celledubas.
3. Troisièmerang:1+1=0avecretenue.Baissezlesdeuxfiches
etposezlejetonau-dessusdelafichesuivantedu8.
4. Quatrièmerang:0+0=0,maislaretenues'ajoute,donc1.
Haussezlafichedubasetécartezlejeton.
Findel'opération.Nouslisonslerésultatdansla lignedubas:00001011doncendécimal8+2+1=11.Lecompteestbon.
FIGURE4.7:Additionbinairejusteavantdereporterlaretenuesurlebitdu8.
Lorsquevousarrivezsurunnouveaurangavecuneretenueetquecerangencréeunenouvelle:
» l'addition1+1dunouveaurangdonne0danslerangpuisvous
rajoutezl'ancienneretenue.
» lanouvelleretenuedurangsepropageàsonvoisindegauche.
Etquandceladéborde?Sivouspartezd'unoctetbienplein(valeurdécimale255):
11111111
etquevousvoulezajouterun,vousarrivezà:
00000000
Vousvousretrouvezavecuneretenuequis'estpropagéedurang1aurang8,puisesttombéeendehorsdunombre.Cetteretenueapourtantbeaucoupdepoids,puisqu'ellevautdeuxfoisplusquelebitdegauchequivaut128(donc256).
Cela se nomme un débordement et le processeur détecte cela en armant un petitindicateur (un drapeau,overflow flag). Le programmeur pourrait en être averti s'iltravailledansunlangagequilepermet(l'assembleur).Commevousleverrezdanslapartiesuivante,deuxcaspeuventseproduire:
» Vousavezprévenulesdébordements.Vousavezchoisiuntypede
donnéepluslarge(parexemplesurdeuxoctetsaulieud'un).Dans
cecas,laretenuevientmettreà1leprochainbit,leneuvièmeetla
valeurstockéeestbien256:
0000000100000000
» Vousn'avezrienprévu.Laretenueestperdue,leprocesseuragite
sondrapeaudanslevideetvoustravaillezavecunevaleurfausse
(0aulieude256).Nousferonsdéborderdesvariablesdansla
Partie3.
Moralité:unhumainavertienvaut10(enbinaire).
Exercice5:-1etsoustractionsenbase2Voyonsmaintenantcommentsoustraire1àunevaleurbinaire.Parcequeceseraittropfacile, nous ne repartons pas de la dernière valeur. Remise à zéro immédiatedemandée(souventabrégépar«RAZ»danslesordinateurs).
Mettez un jeu de huit fiches de côté. Procurez-vous le jeton de retenue négative,encore jamaisutilisé(lasecondepiècedemonnaieou le jetond'uneautrecouleur).Cetteretenuefonctionnedanslesensinversedelapremière:ellenes'ajoutepasaurangdegauche,maisluiemprunteun1.
Positionnezlesfichespourcoderlavaleurdécimale16.Ilsuffitdehausserlaseulefichedes16,lacinquièmeenpartantdeladroite(24).
Nous allonsôter 1 à lavaleurdedépart.Facile, la fichedes16 est haussée, on labaisse,etletour…
n'estpasjouédutout!Résultatzéro!
Enbaissantlafichedes16,nousavonssoustrait16_d,pas1(vousavezremarquéquepour lavaleur1, il est inutiledepréciser si c'estenbasebinaireoudécimale).Enfaisant mentalement le détour par le décimal puis reconversion, on devine déjàque16_dmoins1,c'est15_d,soitlesfichesdes8+4+2+1,lesquatrefichesdedroitehaussées.Binairementparlant:
00010000
-00000001
-----------
=00001111
C'est bien le bon résultat, mais comment comprendre les étapes de la soustractionposéeci-dessus?
Tournons-nousverslatabledevéritédelasoustraction:
Tableau4.2:Tableaudevéritédelasoustractionbinaire.
EntréeA EntréeB Sortie Retenuenégative
0 0 0 0
0 1 1 1(empruntaubitdegauche)
1 0 1 0
1 1 0 0
LesAnglaisdistinguentlaretenuepositiveCarrydelaretenuenégativeBorrow.
Faisonsun testmentalplus simple avec10_d (1010)moins6_d (0110)quidevraitdonner4_d(netouchezpaslesfiches):
1010//(1fois8+1fois2=10_d)
-0110//(1fois4+1fois2=6_d)
------
0100
Nouspartonsdeladroite:
1. pourlesbitsderang1,0-0donne0.
2. pourlesbitsderang2,1-1donne0aussi.
3. pourlesbitsderang3,0-1n'estpaspossible.Onemprunte
le1àgauchepourpouvoirposer10-1,cequidonne1.
4. pourlesbitsderang4,cen'estplus1-0,puisquenousavons
consomméce1aveclaretenuenégativedurangprécédent.
Donc,c'est0-0quidonne0.
Onobtientbien0100,c'est-à-dire4_d.
Revenons à notre jeu de fiches et relisons la soustraction qui nous avait laissésperplexes:
00010000
-00000001
-----------
=00001111
Nouspartonsdeladroite:
» Pourlesbitsderang1,0-1n'estpaspossible.Onempruntele1à
gauchepourpouvoirposer10-1,cequidonne1.Maisiln'yapas
de1justeàgauche.Ilvafalloirpropagercetteretenuenégative
jusqu'àtrouverun1!
» Pourlesbitsderang2,0-0+laretenuedonne1aussi.
» Pourlesbitsderang3,0-0+laretenue(quinefaitquepasser)
donne1aussi.
» Pourlesbitsderang4,0-0+laretenuedonne1aussi.Onn'a
toujourspasremboursélaretenueempruntée.
» Pourlesbitsderang5,enfinontrouveun1qu'onimputeau
remboursementdelaretenuenégative.Ilreste0-0donc0.
Nousarrivonsbienaurésultat,00001111.
FIGURE4.8:Résultatde16décimal-1.
Pourl'instant,nousesquivonslecasd'unrésultatnégatif.
Exercice6:multiplicationenbase2Commepourl'additionetlasoustractionenbase2,ilfautcommencerparrevoirlesrèglesdemariage,c'est-à-direlatabledevéritédelamultiplicationbinaire.Ellen'ariendebizarre.Ilfaut1desdeuxcôtéspourobtenir10:
Tableau4.3:Tableaudevéritédelamultiplicationbinaire.
EntréeA EntréeB Sortie
0 0 0
0 1 0
1 0 0
1 1 1maisattention!
Il y aunpiège : 1 fois1donnebien1, dans toutes lesbasesde l'univers,mais10fois10nedonnepas10,dansaucunebase,pasmêmeenbinaire.
10_b fois10_bdoitdonner100_b.Posons l'opération.Nousnous limitonsàquatrebits et utilisons le symbole adopté en informatique pour la multiplication,l'astérisque:
0010
*0010
------
0000
+0010
------
00100
Onprend d'abord tous les chiffres du premier nombre qu'onmultiplie avec un seulchiffredubas(0010*0=0000),puisdemêmeaveclesecondchiffredubas(0010*1=0010)maisendécalantcommeenmultiplicationclassiqueetontermineparuneaddition.(Onévitelesdeuxautresrangsquisontnulsici.)
Nouspartonsdeladroite:
» Pourlesbitsderang1,0fois0donne0.Toutvabien.
» Pourlesbitsderang2,1fois1donne1.Maiscesdeux1pèsent
deuxfoisplusquedanslepremierrangdesunités.Aulieud'écrire
un0danslerang2durésultat,ondoitécrire10dansles
rangs3et2.
Lavaleur0100correspondbienà4_d.
Un second essai pour voir. En général, mieux vaut poser le plus grand nombre enpremier.Nousmultiplions7décimalpar3décimal:
0111
*0011
------
111
+111
+000
------
10101
FIGURE4.9:Résultatdelamultiplicationde0111par0011.
Commeenmultiplicationscolaire,nousmultiplionstoutelavaleurduhautparunseulrangdubasàlafois.
» Aveclerang1,111fois1donne111.
» Aveclerang2,111fois1donneaussi111,maisavecdécalage
d'unepuissance.
» Aveclerang3,111fois0donne000.
Ilneresteplusqu'àfairelesadditions:
» Aveclerang1,1plus0donne1.
» Aveclerang2,1plus1donne0,avecretenue.
» Aveclerang3,1plus1donne0+retenue,maisilfautdéposer
l'ancienneretenue,donc1.
» Aveclerang4,1plus0+donne1plusretenuedonne0+retenue,
quenouspropageonsdanslenouveaurang5.Onobtient:
00010101
soit16_d+4_d+1_d=21_d.
Exercice7:divisionenbase2La division est une série de soustractions.C'est donc plus long à réaliser pour leshumainscommepourlesordinateurs.
Nous n'utilisons plus nos fiches ici. Il en faudrait une bonne poignée. Posons unedivisionbinaireentre15_det5_dquidevraitdonner3_d.
1111|101
----------
-101|11
0101|
-101|
00|
Première étape : dans 111, on trouve 101 qu'on soustrait, reste 010.On pose 1 enquotient.
1111|101
----------
-101|1
010dereste
Deuxièmeétape:ondescendledernier1de1111àdroitedurestepourobtenir101auquelonsoustraitlediviseuretleresteestnul.Onpose1enquotient.
1111|101
----------
-101|11
0101|
-101|
0dereste
Lequotientestexactementégalà11binaire,donc3_d.
Etsilerésultatdeladivisionnetombepasjuste?Si une division entre deux entiers binaires ne tombe pas juste, il y aura un reste(modulo)quiseraperdu.Pournepas leperdre, il faututiliserun formatdecodagedes valeurs non naturel, le format flottant qui est présenté plus bas. Mais avantd'étudier ce problème de division non entière, voyons comment faire lorsque lerésultatestinférieuràzéro.
Arrivé en ce point du chapitre, vous aussi rirez de la boutade suivante : « Il n'y aque10sortesdepersonnes:cellesquisaventcompterenbinaireetlesautres.»
LesnombresbinairesnégatifsDans nos calculs humains, pour noter une valeur négative, nous ajoutons le signemoinsàgauche.Engénéral,ilyatoujoursunepetiteplaceàgauchedunombrepourajouterunsignemoins.
Maislesautomatesn'ontpasdeplaceentrop,eux.Sinousrepartonsdenotrepaquetdehuit fiches-bits, ilnousfaut fairede laplacepour lesigne.Parconvention,nousdironsquelesigneestnégatifs'ilvaut1.
Nousdevonssacrifierunefiche.
1. Prenezlafichelapluslourde,celledu128.
2. Retournez-laetécrivezengrosenhautlesignemoinspuis
reposez-laàgauchedesautres.
FIGURE4.10:Lanouvellefichedesigne.
Et voilà ! Nous savons gérer des valeurs négatives. Nous, oui, mais les circuitslogiquesd'unordinateurdoiventmaintenanttesteravantchaqueopérationsi lesigne
estpositifoupasafinderéaliserl'opérationdedeuxfaçonsdifférentes,commenouslesavonsnaturellement.Cen'estpastrèsefficace.Uneautresolutionaététrouvée.
Parmanque de place, nous ne pouvons pas donner plus de détails,mais la paradeconsisteàstockertouteslesvaleursnégativesparinversiondechaquebitpuisajoutde 1. Cela s'appelle le complément à deux. La machine peut ensuite continuer àtraiteradditionsetsoustractions,positifsetnégatifs,delamêmemanière.
Unexemple.Cherchonsàcalculer+4-6.
Pourobtenir-6,nousinversonstouslesbitsde+6(leNONlogique):
11111001
etnousajoutons1:
11111010
Lerésultatestbiennégatifpuisquelebitdegaucheestà1.Aprèscetteconversion,iln'yaplusquedesadditions,puisque+4-6estidentiqueà+4+(-6).Vérifions:
00000100//Valeur+4
+11111010//Cettevaleurest-6encomplémentà2
-----------
11111110//C'est-2encomplémentà2
Pourvérifierlerésultat,nousfaisonsunnouveaucomplémentàdeuxdesseptchiffres(oublionslesigneici):l'inversiondes1111110donne
s0000001
etl'ajoutdu1donnelavaleurabsolue:
s0000010
Ils'agitbiende2aveclesignemoins,donc-2.Faisonsunautreessaiavec6-4:
+00000110//Cettevaleurest+6
11111100//Valeur-4
-----------
00000010//C'estbien+2
Encomplémentà2,ledébordementdelaretenuen'apasd'importance.
Demi-bitetquartdebit?Tous les calculs binaires faits jusqu'ici donnent des résultats entiers. Les divisions«injustes»laissentperdrelereste,aupointque5divisépar2donne2,cequisemblefaux.Quefairedu0,5?Dèslespremierscalculateurs,ilafallutrouverunesolutionpourfairecohabiterlesvaleursnumériquesbinairesetlefaitqu'ilpouvaityavoirunepartie fractionnaire, derrière la virgule, inférieure à 1. Après tout, les premierstravauxqui ont été confiés à desmachines étaient les calculs de tir pour les armesbalistiques,etilfallaittaperdansle1000!
Unbitestcommeunatome,onnepeutpaslecouperendeux,nienquatre.Lasolution,devenueuniverselle,consisteàreprésenterlavaleurdansleformatditscientifique.
Lasuitedecettesectionestunpeutouffue,maisellevavouspermettredecomprendrepourquoi dans un ordinateur les valeurs non entières ont souvent un petitmais réelmanquedeprécision.Voiciunnombredécimalécritauformatscientifique:
-0,62s'écrit-6,2x10-1
Une telle écriture se compose d'un signe, d'un corps appelé mantisse et d'unepuissancededixappeléeexposant.Lebutestden'avoirqu'unseulchiffreavant lavirgule.C'estpourquoionditquelavirguleflotte;onlafaitglisserversladroiteoula gauche selon les besoins du nombre jusqu'à n'avoir qu'un chiffre dans la partieentière.
En binaire, on garde lemêmeprincipe : un bit de signe, unemantisse (les chiffressignificatifsramenésaprèslavirgulesaufun)etunexposant.
Pourlesigne,pasdesouci.
Aprèsavoirconvertilapartieentièreenbinaire,oncherchelespuissancesnégativesdedeuxquicomposentlapartiefractionnaire.Eneffet,toutdoitêtreconvertienbasedeuxpourqueleprocesseursachefairedescalculsaveclavaleur.
Si 21 vaut deux en décimal et 20 vaut 1, quelque chose de plus petit que 1 vaut 2puissancecombien?
Lespuissancesnégativesde2!Destréfondsobscursducosmos,voilàqu'arriventlesastronefsblindésdelagalaxieIEEEetleurscanonsàpuissancenégative.
Fausse alerte. 2-1, c'est tout bêtement 1/2 (0,5). Comme au comptoir. Et 2-2 ?C'est1/2de1/2,donc1/4(0,25).Vousdevinezlasuite.
La Figure 4.11 propose un tableau des puissances négatives de deux. Nous avonssélectionnétouteunesériedevaleurs(engras).Lasommeestaffichéeenbas.Nous
cherchionsàobtenir0,6enadditionnantdespuissances,maisdescendusjusqu'à2-32,nousnetombonstoujourspasjuste.Cecidit,laprécisionestdéjàbonne.
Partonsdelavaleurdécimale2,751.Nousécartons lapartieentièreaprèscodageen binaire (qui donne 0010). Intéressons-nous à la partie fractionnaire. Le jeuconsisteàépuiserlavaleurencherchantàappliquerdespuissancesnégativesdedeuxdécroissantes(voirlaFigure4.11.).Nouspartonsde0,751:
0,751*2=1,502.
Le1avantlavirgulesignifieque2-1contribueàlavaleuretlepremierbitaprèslavirguleseraà1.Onjettelapartieentièrepourgarder0,502.
0,502*2=1,004.Idem,2-2convient,deuxièmebità1.Ilreste0,004.
0,004*2=0,008//Pasde2-3
0,008*2=0,016//Pasde2-4
0,016*2=0,032//Pasde2-5
0,032*2=0,064//Pasde2-6
0,064*2=0,128//Pasde2-7
0,128*2=0,256//Pasde2-8
0,256*2=0,512//Pasde2-9
0,512*2=1,024//Lebit2-10seraarmé(ouf)
0,024*2=0,048//Pasdebit2-11
0,048*2=0,096//Pasdebit2-12
0,096*2=0,192//Pasdebit2-13
0,192*2=0,384//Pasdebit2-14
0,384*2=0,768//Pasdebit2-15
0,768*2=1,536//Lebit2-16seraarmé
0,536*2=1,072//Lebit2-17seraarmé
...etc
N'allons pas plus loin.Nous avonsdéjà unevaleur assez proche.Piochonsdans letableaudelaFigure4.11:
2-1+2-2+2-10+2-16+2-17
c'est-à-dire
0,5+0,25+0,0009765625+0,0000152587890625+
0,0000762939453
Le total approché est égal à 0,750999450683594.Avec 23 chiffres binaires, on nepeutpascoderexactementunevaleuraussi«simple»endécimalque0,001.Notrepartiefractionnaireestcodée11000000010000011.
Nousavionslaissélapartieentière(2)donc10.Pourqu'iln'yaaitqu'unchiffreavantlavirgule,ondivisepardeuxetonajouteunàl'exposant.C'estdecetteopérationqueprovient l'expressionvirgule flottantepuisque lavirguleglisse jusqu'àn'avoirqu'unchiffredanslapartieentière.
La norme IEEE754 définit la convention de codage en virgule flottante sur 32 bits(simple précision ou float) ou 64 bits (double précision) endéfinissant3composantes:
» lesigneSestlebitdepoidsfort(leplusàgauche);
» l’exposantEestcodésur8ou11bits.Ilpeutdoncprendreune
valeurentre-126à+127(simple)ou-1022à+1023(double);
» lamantisseM(bitsaprèslavirgule)estreprésentée
sur23ou52bits.
FIGURE4.11:Quelquespuissancesnégativesde2.
Lecodagesurunmotde32bitssefaitsouslaformesuivante:
S8bitspourE23bitspourM
Ilya toujoursun1binaireavant lavirguleune fois lenombre formaté,donconneperdpasuneplaceàlemémoriser.
Lareprésentationenvirguleflottanteaéténormalisée(normeIEEE754)afinquelesprogrammesaientuncomportement identiqued'unemachineà l'autre.Pourfairedesessais,voyezparexemplelapageanglaisesuivante:
http://www.binaryconvert.com/convert_float.html
N'oublionspaslabase16(hexadécimale)
Pour conclure cette visite des nombres, il serait dommage de ne pas faire laconnaissancedelabase16.
Comment?Encoreunebase?Oui,maiscelle-ciestultra-facile.C'estaussi simplequedeuxfoisdeuxfoisdeuxfoisdeuxfontseize.
La valeur seize est unmultiple de deux. C'estmême exactement 24 qui occupe undemi-octet(1111)ouquartet.
Autrementdit,pourdésignerunevaleurbinairesurhuitbits,onpeutsecontenterdedeuxchiffreshexa.
Mais il faut plus de dessins de chiffres qu'en base 10. On a choisi les premièreslettresdel'alphabetpourcompléter.Comptonsde0à15danslesdeuxbases:
Base10:
0123456789101112131415
Base16(hexadécimale):
0123456789ABCDEF
Lesconversionssontplusfaciles.Ontraitelesbitsparpaquetsdequatre.Partonsdelavaleurdécimale195.Enbinaire:
11000011
Enhexa,onséparelesdeuxquartets:
1100vaut(8+4+0+0=12)doncCenhexa
0011vaut(0+0+2+1=3)donc3enhexa
Lavaleur195_ds'écritC3henhexa.Demême,FFhvaut255_d(11111111).
Pourlesvaleursenbase16,onajouteunhminusculeaprèslavaleur(F28Ah).Dansplusieurslangages(C,C++,Java),onutiliseaussilepréfixe0xcommedans0xF28A.EnHTML,lesvaleurshexadécimaless'écriventavecundièseenpréfixe:#F28A.
La notation hexa fait gagner beaucoup de place tout en étant facile à convertir enbinaire.Elleestbienpluscompactequeladécimale.Comparezvous-mêmeavecleplus grand entier binaire sur 32 bits qui représente un nombre à 10 chiffres endécimal:
Décimal:4294967295
Binaire:11111111111111111111111111111111
Hexa:FFFFFFFF
Chacundesgroupesde2chiffresdelavaleurhexacorresponddirectementàunoctetdelavaleurbinaire.C'esttrèspratique.
RécapitulonsLesautomatesduprécédentchapitrepossèdentaveclabasedeuxprésentéeicicequileurmanquaitpourproduirel'enfantprodige:l'ordinateur.
Leprochainchapitrevanouspermettredefaireconfluercesdeuxdomaines.
D
Chapitre5Lesablequipense
DANSCECHAPITRE:
» JeuxdeBoole
» Uneportedoitêtreouverteoufermée
» LaCPUauneALU
ansleChapitre3,nousavonsvisitélesgrandesétapesdel'inventiondemachinesen terminant avec les tubes et les transistors qui ont été d'abord exploités pourleurfonctionanalogique:produireunsignalélectriquedesortiepluspuissantque
lesignald'entréeenépousantplusoumoinsfidèlementsesvariations.
DansleChapitre4,nousavonsapprisàcompterenbase2plutôtqu'enbase10.Celapeut constituerundivertissement aumême titreque résoudredesgrillesde sudoku,maissinousyavonsconsacréunchapitre,c'estsansdoutepouruneraisonpluslourdedeconséquences.
L'éclosionde l'informatique,c'est la fusionducomptageenbase2etduconceptdecommutation électrique pour simuler la logique (vrai ou faux), ce qui a étédéfinitivement réalisé au milieu du XIXe siècle. Il ne restait ensuite plus qu'àcombinerdescircuitsélectriquessecomportantcommedesinterrupteurss'ouvrantouse fermant selon l'une ou l'autre des règles de la logique binaire.Voyons donc cesrègles.
JeuxdeBoole!S'appuyantsurlesthéoriesdelalogiqued'Aristote,l'AnglaisGeorgeBooleadéfinivers1840desopérationslogiques(unealgèbre)permettantdesymbolisercegenrederaisonnement:
SItouslesanimauxquivolentsontdesoiseaux
ETSIjevoisvolerunanimal
DONCcetanimalestunoiseau.
LesdeuxconditionsSIsontappeléesdesprémisses.CesprémissessontmariéesparlemotET.Ellesdoiventêtrevraiestouteslesdeuxpourquelaconclusionpuisseenêtredéduite.Logique,non?Desobjections?
Onpeutobjecterque1)estfauxpuisqu'ilyadesécureuilsvolantsetdeschauvesourisetque2)estfauxparcequ'onpeutvoirvolerdesfeuillesmortes.Biensûr,avecleslangageshumains,onpeutdiscuterdecequiestunanimaletdecequ'estexactementl'actiondevoler.Parexemple,est-cequ'unavionsaitvoler?
Dans le monde physique, les situations incarnant correctement le ET logique sontcourantes.
Supposonsqu'unemissionconsisteàposerunevalisesurunetable(solide).Lavaliseest trop lourde pour un seul homme.Deux hommes,messieursLunion et Félaforce,sontdisponibles.Quatrecassontpossibles:
» Personnenevientlasoulever.Lavaliseresteparterre.Succès=
zéro.
» M.Félaforcevientessayer.Lavaliseresteparterre.Succès=zéro.
» M.Lunionvientessayer.Lavaliseresteparterre.Succès=zéro.
» Enfin,ilstententlecoupàdeux.Ilssoulèventlavalise.Succès=un.
Si on allège la valise pour lamission suivante, il suffit qu'undes deux se présentepour faire réussir lamission.C'est leOU logique.Lavaliseest soulevéedèsqu'aumoinsundeshommesseprésente.
AETBouAOUB?Ce qui nous intéresse, c'est de voir comment les règles de la logique booléenne(hommageàBoole)vontpouvoirnousserviràcréerunemachinecapabledefairedescalculsenbasedeux.
Lesdeuxchiffres0et1delabasedeuxcorrespondentdirectementauxdeuxnotionsVraietFaux.Surtout,ilsycorrespondentsansdiscussionpossible.Enmathématiques,iln'yapasdevaleur«presquevraie»ou«presquefausse».Simplifionslaformuleprécédente:
1)SIVRAI
ET
2)SIVRAI
R)DONCVRAI
Le ET est un opérateur (comme le signe plus de nos additions). Il produit uneconséquence(laconclusion)encombinantdesdeuxopérandes(lesprémisses).
LeETcorrespondàdeux interrupteursplacés l'unaprès l'autreensérie. Il fautquetousdeuxsoientferméspourquelecourantpasse.
Pourquelaconclusionsoitvraie,ilfautquelesdeuxprémissessoientvraies.Danslestroisautrescas(valisetroplourde),lerésultatestfaux.
Danslecasoùlavalisepeutêtresoulevéeparunseulhomme,laformuledevient:
1)SIVRAI
OU
2)SIVRAI
R)DONCVRAI
LeOUcorrespond à deux interrupteurs placés l'un à côté de l'autre enparallèle. Ilsuffitquel'undesdeuxsoitfermépourquelecourantpasse.
Pourcomplétercettepairefondamentale,nousajoutonsunraisonnementencoreplussimple:direlecontraire.C'estlafonctionNONquin'abesoinqued'uneentréedontelleinverselavaleur.
PorteslogiquesLevisionnaireClaudeShannonenafaitlapreuveen1938:cestroisraisonnementsélémentaires ET, OU et NON peuvent être simulés physiquement dans des circuits(pourunefois,lemondephysiquesimulelemondemental).Cescircuitssenommentdesporteslogiques.
Dessymbolesgraphiquesontétéchoisispourchaquetypedeporte(nousprenonsleurformatanglo-saxonplusesthétiquequeleformatcarré).
L'opérationlogiqueET(AND)Enfonctiondelavaleurdedeuxentrées(deuxprémisses),onpeutdresserlatabledevéritéduET:
Tableau5.1:ETlogique.
EntréeA EntréeB Sortie
0 0 0
0 1 0
1 0 0
1 1 1
Vousremarquezquec'estunesortedetabledemultiplication.
FIGURE5.1:UneportelogiqueET(AND).
L'opérationlogiqueOU(OR)
FIGURE5.2:UneportelogiqueOU(OR).
Demême,onpeutdresserlatabledevéritéduOUlogique.
Tableau5.2:OUlogique.
EntréeA EntréeB Sortie
0 0 0
0 1 1
1 0 1
1 1 1
Vous remarquez que c'est une sorte de table d'addition, sauf que nous savonsque 1+1 fait 10 et non 1. Dans cette version élémentaire, nous ne gérons pasl'apparitiond'uneretenue.Celaviendra.
L'opérationlogiqueNON(NOT)LafonctionNONestévidemmentlaplussimplequisoit,maiselleestindispensable.Silesignald'entréeestà1,lasortieestà0.
FIGURE5.3:UneportelogiqueNON(NOT).
Danslesdescriptionsd'algèbrebooléenne,unevaleurinverséeparunNONestécriteavecunebarrehorizontaleau-dessus.
AutresopérationsEn combinant ces trois fonctions logiques primordiales, il est facile de créer desvariantes:
» LeET-NON(enanglaisNAND)quiajouteuninverseuràlasortiedu
ET.LerésultatfinalestFAUXseulementsilesdeuxvaleursd'entrée
sontVRAIES.
» LeOU-NON(enanglaisNOR)quiajouteuninverseuràlasortiedu
OU.LerésultatfinalestVRAIseulementsilesdeuxvaleursd'entrée
sontFAUSSES.
Toutessortesdecombinaisonssontensuitepossiblesdontuneestconsidéréecommeélémentaire : leOUexclusif.C'estunOUquiexclut lecasoù lesdeuxentréessontVRAIES. Le résultat n'est VRAI que si une seule des deux entrées est VRAIE. Lecircuitpermetdoncdetesterunedifférence.
LeOU-EXporteunnomanglaisdigned'unfilmdescience-fiction:XOR.Voicisonsymbole:
FIGURE5.4:UneportelogiqueOU-exclusif(XOR).
Etvoicisatabledevérité.
Tableau5.3:OUexclusiflogique.
EntréeA EntréeB Sortie
0 0 0
0 1 1
1 0 1
1 1 0
La fonctionOU exclusif ressemble plus que leOU normal à l'addition binaire vuedanslechapitreprécédent,puisque1+1=10,donc0dansl'unité.Ledéfautestquelaretenueestperdue.Ilvafalloircombiner.
CircuitscombinatoiresLa première opération utile que l'on va chercher à automatiser en combinant desporteslogiquesestl'additionexactededeuxvaleursbinaires.
En reliantd'une certaine façonuneporteOUexclusif et uneporteET,on arrive aurésultat.C'estledemi-additionneur.
Ledemi-additionneurCecircuit«sait»fairelasommededeuxnombresbinairesAetB.Puisqu'ilréunitdeux portes, il offre deux sorties, une pour la valeur des unités (S) et une secondepourlaretenue(CpourCarry).
FIGURE5.5:Undemi-additionneur.
Arrêtons-nousuninstantsursonfonctionnement:
» LasortieSestà1seulementsiunedesdeuxentréesestà1,parce
quec'estuncircuitXOR.Ilpermetderépondreaucas0+0=0;la
retenueCresteàzéro.
» QuandAetBsontà1,celacorrespondàl'addition1+1qui
donne10.Lasortieestbienà0,cequicorrespondau
calcul1+1=0plusretenueà1.
» Justement,lasortiederetenueCnepeutpasserà1quesiAetB
sontà1,carc'estuncircuitET.
Cecircuit incarnedoncphysiquementuneadditionbinaire.C'est ledébutd'une trèsgrandehistoire.Voicilatabledevéritéducircuit.
Tableau5.4:Demi-additionneur.
EntréeA EntréeB SortieS RetenueC
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1(car1+1=10)
Cecircuitestundemi-additionneurparcequ'ilneprévoitpasderéutiliserenentréelaretenued'uncircuitprécédent.
Eninjectantlasortiedudemi-additionneurdansunautredemi-additionneurenmêmetempsquelaretenue,onobtientunvraiadditionneurcomplet.
AdditionneurcompletUnadditionneurcompletestuncircuitcapabledefairelasommede3bits:lesbitsAet B à additionner et le bitCiqui est la retenue d'un calcul précédent. Le circuitpossèdeunesortieSetuneretenueàpropagerCs.
Enpratique,onenchaîneencascadelenombred'additionneursqu'ilfautpourtraiterunevaleursur8,16,32ou64bits.
FIGURE5.6:Unadditionneurcomplet(full-adder).
Voicilatabledevéritédel'additionneurcomplet.
Tableau5.5:Additionneurcomplet.
RetenueCi EntréeA EntréeB SortieS RetenueCs
Lorsqu'iln'yapasderetenueentrante:
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 0
Avecretenueentrante:
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
Pour mémoire, sachez que les autres circuits combinatoires fondamentaux sont leregistreàdécalageetlemultiplexeur.
Jemesouviens…(circuitsséquentiels)Savoircompter,c'estbien,maispourfaireplusd'ununiquecalcul,ilfautsesouvenirdu résultat précédent. Se souvenir, c'est gérer le temps.C'est décider à unmomentprécisque lavaleurprésenteà l'entréed'uncircuitdoit êtremaintenueen sortieducircuitjusqu'ànouvelordre.Cegenredecircuitsenommeunverrououunebasculeetpermetdecréerunecellulemémoirepourstockerunevaleurbinaire.
C'estuncircuitséquentielparcequesonchangementd'étatdépenddel'étatantérieur.Celivreétantconsacréàlaprogrammation,nousn'avonspasbesoind'entrerdanslesdétailsdesfonctionsmémoire.Contentons-nousdedistinguerlesmémoiresstatiques(SRAM)etlesmémoiresdynamiques(DRAM).
MémoirestatiqueS-RAMUnecelluledemémoirestatique(S-RAM)estbaséesuruncircuitbasculequirequiertunedizainedeporteslogiques.Lesaccèssonttrèsrapidesmaislescomposantssontpluscoûteuxàproduirequel'autregrandetechnologie,celledelamémoireD-RAM.
L'approcheS-RAMestréservéeauxregistresinternesduprocesseurquidoiventêtrelesplusrapidespossiblescartouteslesvaleursytransitent.LaS-RAMsertaussiauxblocs mémoire intermédiaires entre la mémoire principale et le processeur, etnotammentauxtamponscachesduprocesseurquialimententsontravail.
MémoiredynamiqueD-RAMLatechnologieD-RAMestbeaucoupplussimpleàfabriqueretoccupebienmoinsdeplace que sa collègue S-RAM. Chaque cellule se résume à un transistor et uncondensateur.Maistoutavantageasesinconvénients.
Le D dans D-RAM signifie Dynamique, ce qui est une manière d'avouer que lamémoireD-RAMestunemémoirequiperdlamémoire!Eneffet,ladonnéebinaireest stockée sous forme d'une charge électrique dans un condensateur (un petitréservoir d'électricité), et cette charge disparaît peu à peu. Pour éviter qu'elle soitperdue, il faut récrire chaque cellule environ quinze fois par seconde. Oui, parseconde!Ilfautluirafraîchirlamémoire,etc'estd'ailleurslenomdecetteopérationdegymnastiquecérébrale.
L'opérationestjouable,puisqu'enuneseconde,onpeutréaliseraumoinsdixmillionsd'opérations de lecture ou d'écriture. En perdre quelques pour-cents pour cause derafraîchissementresteacceptable.
Le circuit D-RAM est devenu le composant quasi universel des mémoires de nosordinateurs.En1970,Intelfabriquaitunepucede1024bits(128octets).En2015,ontrouveàbascoûtdes«barrettesmémoire»D-RAMpouvantstocker32milliardsdebits(4Go).
TuringetVonNeumannNousavonsvuquelamachinedeBabbageutilisaitdesjeuxdecartesséparéspourlesopérations et pour les valeurs. Vers 1945, deux théoriciens, John von Neumann etAlan Turing, sont arrivés à la même idée : stocker les opérations dans la mêmemémoireque lesdonnéeset lire lesopérationsuneparunepour les exécuter.C'estl'architectureVonNeumann. Ce n'est pas la seule approche possible,mais elle estdevenuequasi universelle.L'architectureHarvard utilise deux canauxdistincts (desbus)versdeuxmémoiresdistinctespourlecodeetlesdonnées.
Leprocesseur(CPU)Des portes par centaines, par milliers, puis par milliards, voilà ce qu'est unprocesseur. Et au coeur du processeur, l'Unité Arithmétique et Logique (ALU) quieffectuetouteslesopérationsdemandéesparvotreprogramme:
» desopérationslogiques:ET,OU,NON,OUexclusif;
» desopérationsarithmétiquesbaséessurlesprécédentes:
addition,soustraction,etc.;
» desopérationsdetransfertdepuisouverslamémoire;
» dessautsetbranchementsversuneautreinstructionquecelle
situéeàl'adressesuivante.
L'ALUavecsesassistants lit lesprochainesinstructionsduprogrammeenmémoire,ainsiquelesdonnées,modifiecesdonnées,engénèred'autresetstockeletoutdanslamémoire.Une horloge (clock) donne la cadence et fait passer l'ensemble d'un étatdéfiniausuivant.
Pourunêtrehumain,multiplierdeuxnombressur10chiffresprendcinqminutes.Avecunemachine à relais, lamême opération prend 2 secondes.Avec des tubes à vide(ENIAC), un millième de seconde. Un processeur des années 2000 réalise cetteopérationdixmillionsdefoisenuneseconde.
LaFigure5.7proposeunevued'ensembled'unprocesseurdéjàassezancien(1980).C'estunIntel8085quiintègre6500transistors.Onparvientpresqueàlesdistinguerunparun.Montrerunprocesseurplusrécentdanslaplacedisponiblesurcettepagenelaisseraitvoirquedesplagescolorées.Ladensitédesprocesseursaétémultipliéeparunmillionenquaranteans.
Ondiraituneville,mieux,unemégapoleavecsesquartiers.Effectivement,onparled'architecturedesprocesseurs.
Ilexistedessimulateursdeprocesseurs.CeluideLajosKintliestconsacréaupremiermicro-processeur du monde, le 4004 Intel de 1971. Voici une vue générale de celogicieltrèsinstructifpuisquel'onpeutvoirfonctionnerleprocesseurgrâceaumodeAnimation.
Pourtrouverlapagedecetoutil,cherchezsurleweb«Kintli4004simulator».
FIGURE5.7:Microphotographied'unprocesseurIntel8085.
FIGURE5.8:Lesentraillesd'unprocesseurenfonctionnement.
ConclusiondelapartieDusableastucieusementgravépour incarnerdesopérationsen logiquebooléenne :nousavonstoutcequ'ilnousfautpourcréerdesmondesvirtuels.
La prochaine partie, la plus importante du livre, est consacrée à l'exploitation despossibilitésetdeslimitesdecettemachineparl'écrituredeprogrammes.
IIIFondamentaux
DANSCETTEPARTIE
Valeurs,donnéesetmémoire
Contrôlerlefluxd'exécution
Distribuerletravail:lesfonctions
Groupesdedonnées:tableauxetchaînes
Constructiondel'exécutable:compilez,liez,dégustez
Profitezdesautres:leslibrairiesstandard
Onmonteenrégime:structuresetpointeurs
E
Chapitre6Dompterlabête
DANSCECHAPITRE
» Ecrivaindecodesource
» Analyseetraisonnement
» Conditionsd'écriture
» Stylesdelangages
» Vueglobaled'untextesource
nchinois, lemotordinateur (diànnao)signifie«cerveauélectrique» .Dans lapartie précédente, nous avons découvert la partie matérielle de ce cerveauélectrique, dans sa version quasiment universelle de nos jours (l'architecture de
VonNeumann).Cet«électro-cerveau»faituneactionàlafois,petitpasparpetitpas(maisilsaitavancerdeplusd'unmilliarddepasparseconde).
«Votremission,sivousl'acceptez,consisteàguidersespas,dupremieraudernier,sansjamaisluilâcherlamain.»
Guiderpasàpasest laborieux.Fairele tourdumondeainsin'estpasenvisageable.C'estcequel'ondésignecommeleniveaudulangageassembleur.
Dès que la puissance des machines l'a rendu possible, on a décidé de créer desvocabulairesdesymbolesrégisparunesyntaxeafindepouvoirformulerdessortesdephrases.
C'estpourquoionparlede« langage»pourdécrire les étapesdeprogressiond'untraitementdevaleurs.Unlangagedeplushautniveauserapluséloignédescontrainteset des détails du processeur et donc plus proche de la façon dont les humainsréfléchissent.
Unécrivainélectrique?Dans tous les cas, le programmeur écrit. Il écrit du code que l'on qualifie de codesource,parcequec'estàcettesourcequepuisel'outildetraductionpourgénérerunesérie illisible de valeurs numériques qui incarnent une image « congelée » duprogramme.
Ce n'est qu'au chargement/démarrage du programme qu'il est rendu actif, vivant, enoccupantdel'espaceenmémoireetdutempsdeprocesseur.
Lestroisétatsphysiquesprincipauxdanslequelpeutserencontrerunprogrammesontdonc:
» codesource:uneséquencedemotsclés,devaleurs,denomset
desymbolesqu'unoutild'analysepeutdécortiquerpourgénérerle
codeexécutable;
» codeexécutable:uneséquencedevaleursentièresmélangeantles
valeurs(données)etlesactions(instructions)dansunétatfigé,
conservénormalementdansunfichierdansunemémoire
permanente;
» programmeactif:uneconfigurationdevaleursdanslamémoire
del'ordinateurencoursdelectureparleprocesseurpourproduire
desmodificationsdecertainesdecesvaleurs.Lerésultatestpar
exempleunefenêtred'application.
Parmices troisformats, lepremierestentièrementàvotrechargeet lesdeuxautressonttotalementautomatiques.
FIGURE6.1:Lestroisvisagesd'unprogramme.
Toutsepasseàl'intérieur!Un programme est une œuvre de l'esprit, comme une œuvre musicale, picturale,choréographique,etc.Unromanciern'estpasunepersonnequiinscritdeslettressurdupapier.Latraceécriten'estqueletémoind'uneactivitémentaleconcentrée.
Le programmeur est le compositeur. Le code source est sa partition, le processeuravec sa cour est l'interprète. Le programmeur est en quelque sorte le Dieu duprocesseur : ce qu'il écrit dans le code source définit totalement le contenu de la«pensée»delamachine.
La responsabilité peut donc être énorme, par exemple quand l'œuvre a pour but degérerlesvaleursmonétairesconfiéesparlesgensàleurbanqueoulesparamètresdesuividesfonctionsvitalesàl'hôpital.
De fait, le résultat tangible, visible, du travail d'un programmeur est une série delignes de texte source, mais ce n'est que le fruit d'un processus mental qui vas'incarnerdanslefonctionnementduprocesseur.
C'estunpeucommeunjoueurd'échecquipenselescoups.Laprochainepiècequ'ildéplacen'estquelerésultatfinald'untraitementmental.
DévelopperunraisonnementLeprogrammeurestunepersonnequisaitjongleravecdesdonnéesenseservantdesoutilsquesontlesinstructions.Cetteséancedejonglerieestunprogramme.
Commeunjongleur,leprogrammeurtravaillebeaucoup:ildécomposesesactions,ilteste plusieurs solutions, il tâtonne pour au final réunir harmonieusement tous lesgestesenunspectaclequ'ilvaexécuter.
Lorsquevous commencez àprogrammer, vous écrivezdu code source en apprenantcommentformulerleschoses.Lesprogrammeurssontsouventdésignéssousletermededéveloppeurs,carilspartentd'uneidéedufonctionnement,idéequ'ilsdéveloppent.
Enpratiquantcetteactivité,vousintériorisezdemieuxenmieuxlalogiquedecontrôledufonctionnementdevotreinterprète,leprocesseur.
Autrementdit, apprendreàécrireducodesourcevous sert àapprendreàpenser, àpréméditer le comportement futur d'unemachine. Pour y parvenir, comme dans lesautresactivitésdel'esprit,vousn'êtespasseuldevantlafeuilleblanche.
ONÉCRITPOURQUI?
Lorsquevousécrivezlecodeouletextesourced'unprogramme,votrelecteur
estbiensûr l'ordinateur,ouplusprécisément l'analyseurducompilateurqui
doit comprendre ce texte pour pouvoir générer le code machine
correspondant.Maiscen'estpasleseuldestinatairedevotreécriture!
Vousécrivezaussipourvoscollèguesactuelsou futursainsiquepourvous-
même. D'autres programmeurs auront (nous vous le souhaitons) envie ou
besoindecomprendrecommentvousavezrésoluunproblème,parexemple
pourl'enrichirouleréutiliserdansunautreprojet.
Une fois que vous terminez un projet, vous passez à autre chose. Si vous
revenez au premier projet après plusieursmois, vous serez ravi d'avoir pris
soindebienprésenterletextesourceetd'yajouterdescommentaires.
Conditionsd'écritureEn débutant en programmation, vous héritez sans régler de droits de succession dutravail des chercheurs, des ingénieurs et des autres programmeurs, et ceci dans denombreuxdomaines:
» normesd'analyse;
» normesdesyntaxe;
» normesdeprésentationetdecommentaires;
» normesdecontrôlequalité.
» Normesd'analyseetdeconception
Dèsquevotreprojetprendunecertaineimportance,vousaurezavantageàutiliserunetechniquepourdécomposer leproblèmeet pour exprimer les étapesde la solution.Vousréutiliserezdesalgorithmes,quisontdesdécompositionsentâchesélémentairesdelasolutionàunproblèmeuniversel:
» convertird'uneunitéversuneautre;
» trierunelisted'éléments;
» trouverlaplusgrandevaleurnumériqueparmiplusieurs;
» calculerunefactorielle;
» vérifierlasoliditéd'unmotdepasse,compresserdesdonnées,etc.
Certains livres de programmation insistent sur la maîtrise des algorithmesfondamentaux.Maispuisquedesprogrammeurstrèscompétentsontdéjàformulécesalgorithmes génériques, autant s'en servir. Il y a tellement d'autres concepts àapprendre.
Vous pourrez adopter une méthode de conception structurée qui vous aidera àdélimiter les sous-ensembles de traitement. Voici quelques termes concernant cesujet:
POO (ProgrammationOrientéeObjets).Cetteapprocheconsisteàcréer
desentitésautonomesnomméesobjetsquicorrespondentau
réel
UML
Conventiond'analysepourmodéliserlesrelationsentre
processusetobjetsbaséesurdesformesgraphiquesstandard
TDD (Test-DrivenDevelopment)pourécrirelesprogrammesdetest
avantlesprogrammesàtester
Client/
Serveur
Pourrépartirlasolutionentreunemachinequifournitdes
traitementsetdesdonnéesetuneautrequilesconsomme
MVC (Modèle/Vue/Contrôleur)pourséparerlestockagedesdonnées,
lesdialoguesavecl'extérieuretlalogiquedetraitement
Patronsde
conception
(DesignPatterns).Permettentdecapitalisersurlesréussites
passéespourconstituerunepalettedemodèlesdesolutions
génériquesréutilisablesetpersonnalisables
Il en existe beaucoup d'autres et cette liste regroupe des techniques normalementséparéesoucomplémentaires.
Ces outils de conception deviennent indispensables dans les grands projets. Vousimaginezlaquantitédeprogrammesd'unsystèmetelquel'informatisationdetouslesservicesde l'Etat.Ce sont lesprogrammesquidialoguent entreeux.Onparle alorsd'urbanismedusystèmed'information.
NormesdesyntaxeCeniveaudenormesesttotalementdéfiniparlelangagequevouschoisissez.ToutelasuitedecettepartieapoureffetdevousprésenterlasyntaxedulangageC.
Considérez pour débuter que dans le texte source, l'alphabet est celui de la langueanglaise. Pas de lettres accentuées, ni de symboles autres que ceux que nousindiquerons.
NormesdeprésentationetdecommentairesPour quasiment tous les langages, le texte source est une suite ininterrompued'élémentsséparésparaumoinsunespaceoucequiéquivautàunespace(tabulation,sautdeligne).
FIGURE6.2:Untextesourceornementé.
Voici un exemple extrême à ne pas suivre. Ce texte source en langage Perl estfonctionnel,maisinconfortableàrelire!
Les//nesontpasbarbaresIl est important et beaucoup plus agréable d'adopter une façon de présenter lesélémentsetdes'ytenir,autrementditd'apprendreàcoderproprement!
Lescommentaires sontprécieux.Certainsprogrammeursvont jusqu'àécrired'abordtouslescommentairesdanslecodesource,puisajoutentlevraicodesourcedansundeuxièmetemps.
PuisquecettepartieseconcentresurlelangageC,voiciàquoiressemblentquelquescommentairesdanslesdeuxformatspossibles:
//Jecommentesuruneligne
//Cecietjusqu'enfindelignen'existepaspour
l'analyseur.
/*Lecoupleouvrant"barreobliqueastérisque"
définitundébutdezonedecommentairesquipeutse
poursuivre
surplusieurslignessansdevoirrépéterl'ouvrant,
mais
ilfautpenseràrefermerlazoneavecsoncollègue
fermant
*/
NormesdecontrôlequalitéUncodesourcepeutcontenirdeuxtypesd'erreurs:
» leserreursdesyntaxe;
» leserreursdelogique.
Lesfautesdesyntaxesontdétectéespar l'outilanalyseurqui faitpartiede lachaîned'outils.Ellessontdoncnécessairementcorrigées,parcequelecodesourcenepeutpasêtretraduitenprogrammetantqu'ilresteuneseuleerreurdesyntaxe.
En revanche, les erreurs de logique que l'analyseur ne sait pas détecter deviennentvotre problème, et parfois celui de l'utilisateur du programme. Ce sont les fameuxbogues,descoquillesduraisonnement.
Bogue est le nom de la coquille des châtaignes. Et les coquilles sont au senstypographiquedesfautesdecompositionchezleséditeursetimprimeurs.
Desoutilsnommésdébogueurspeuventvousaideràtraquerceserreurs.Vouspouvezaussi concevoir des tests pour valider le projet : des tests unitaires pour chaquefonctiondechaquefichiersourceetdestestsd'intégrationpourvaliderl'ensemble.
StylesdelangageLes contraintes, la logique et la façon la plus efficace d'exprimer la solution à unproblèmeontdonnénaissanceàplusieursstylesd'infolangages(des«paradigmes»).Chaque style est plus adapté à certains domaines : calcul scientifique, gestiond'entreprise,créationgraphique,jeux,traitementdusignal,contrôleindustriel,etc.
Onpeutdistinguertroiscatégoriesprincipalesd'infolangages:
» Leslangagesimpératifs,quisontconstituésd'ordrespour
appliqueruneactionàunevaleur(additionner,soustraire,copier,
comparer,...).
» Leslangagesdéclaratifs/fonctionnels,quisontplusabstraits,
plusindépendantsdelamachine,carilsn'indiquentpas
directementcommentfaireleprochainpas.Ilsdéclarentl'état
qu'unevaleurdoitprendreenpartantd'unautreétat.(Nous
simplifions.)
» Leslangagesorientésobjets,quicombinentlesdeuxprécédents
enproposantdedécrirelasolutiond'unproblèmesousforme
d'élémentsautonomes(lesobjets)quiconstituentdeslignées
hiérarchiquesetdialoguentpoursedemanderdesserviceslesuns
auxautres,commeunepetitesociété.Al'intérieurdechaqueobjet,
onretrouvedel'impératif.
Dans toute la présente partie, nous allons nous intéresser au langage impératif parexcellence : le langage C. Nous évoquerons les autres catégories dans la partiesuivante,lorsquenousauronsacquisdesbasessolides.
ConditionsmatériellesdecréationUncrayonetdupapierpourraientsuffireaudépart,maispourconcrétiservotreidéeet la communiquer, il vous faut deux outils principaux (d'autres viendront facilitervotretravail,maisilsnesontpasindispensables):
» Unprogrammepourcréeretmodifierlefichiernumérique
contenantlecodesource(unlogicield'éditiondetexte).LeBloc-
notesdeWindows,TextEditsousMacOSouGeanysousLinux
suffisentpourcommencer.
» Unprogrammepourgénérerlefichierexécutableduprogramme
enpartantdevotrecodesource.Enfait,c'estuneséried'outils
souventdésignéesouslenomdel'und'entreeux:lecompilateur.
Nousexpliquonsdansunchapitreultérieurcommentfonctionne
cettechaînedetraitement.
En annexe, nousmontrons comment trouver etmettre en place un environnement derédactionetdecompilation.
Pour résumer, il vous faut deux logiciels pour créer un logiciel. Nous supposonsévident que tout cela se déroule sur un ordinateur fonctionnant grâce à un systèmed'exploitation(Windows,Linux,MacOS).
Vueglobaled'untextesourceenCCommelestextesdeslangueshumaines,untextesourceestdestinéaprioriàêtreludefaçonlinéaire,delapremièreàladernièreligne.
Laseuledifférenced'importanceestqu'uncodesourceressembleplutôtàces«livresdont vous êtes le héros » . Arrivé à certaines étapes, le lecteur peut choisir depoursuivre la lecture ailleurs qu'à la ligne suivante si une condition lui semblesatisfaite.
De même, dans un code source, la lecture séquentielle est de temps à autreinterrompuepardesindicationsspécialespour:
» demanderdesauterplusieurslignesou;
» relirelemêmegroupedelignesplusieursfoisou;
» allerlireunautregroupedelignespuisrevenirpoursuivreau
marque-page.
Parmilesmotsetsymboles,certainssontfigés.Cesontdesinvariantsqu'ilfautécriretels quels. Ce sont quasiment toujours des mots en anglais comme while,printf(),caseoudessymbolesd'opérateurscomme+et/.Onlesappelledesmotsréservésoumotsclés.
Vousallezrapidementconnaîtrelesmotsréservésdulangagechoisicarilssontpeunombreux(del'ordred'unetrentaine).
D'autresmotssontdéfinisparvous,entenantcomptedequelquesrèglesdenommage.Cesontdesidentifiantspourlesvariablesetlessous-programmes.
Certainesportionssontréservéesàvotreusageexclusif.Cesontlescommentairesquicommencentpasunedoublebarreoblique//oulesblocs/**/.
FIGURE6.3:Vueglobaled'untextesource.
Ilyaenfindessignesdeponctuation.Ilsontuneimportanceextrême.Ilssontlesamisduprogrammeur,s'illesrespecte:
; lepoint-virgule,
() lesparenthèses,
{} lesaccolades,
, lavirgule,
[] lescrochetsdroits,
etquelquesautresmoinsusitéscomme&,|,!.
Enavanttoute!
Rédiger le code sourceapourbutdeproduireun fluxde0etde1dansun fichierexécutable.Cefluxnereprésentequedeuxespècesd'éléments:
» desvaleursnumériquesinertes,lesdonnées;
» desvaleursnumériques«actives»,c'est-à-direreconnuesparle
processeurcommedesactions,desinstructions.
Lesdonnéespeuventêtrededeuxsortes:
» desvaleursnumériqueslittérales(nousabrégeronsparVNL).Ce
sontdesdonnéesausensstrict,.
» desadressesmémoiresymboliséespardesnomsdevariables.Ces
valeursetcesnomsvontpouvoirêtrecombinésdansletexte
sourcesousformed'expressionsgrâceàdesopérateurs.
C'est selon cette approche que nous allons découvrir les éléments du langage deprogrammationC.
Vous pouvez lire toute cette partie à l'écart d'un ordinateur. Lorsque quelque chosedoits'afficher,nousreproduisonslerésultatdanslelivre.
Votreconteneuràcodesource(main)Danstouslesexemplesetextraitsdecodesourcedespremierschapitresdelapartie,nous ne proposons pas de programme entier. Du fait que les exemples sont trèssimples, chacun d'eux peut être testé en insérant les lignes présentées dans uneébauchedetextesourcequiesttoujourslamême.
LISTING6.1EbauchedeprogrammesourceCpourycollerleslignes
d'exemple.
intmain(){
//ICIVOSLIGNES
}
Voussaisissezlegroupedelignesàtesteràlaplaceouaprèslalignedecommentairecommençantpar//.
Il est trop tôt pour expliquer à quoi correspondent les deux lignes qui encadrent letout.Lemotmain()n'a aucun rapport avec unmembre humain. Pour lemoment,tenezceslignespouracquises.
C
Chapitre7Desvaleursauxdonnées
DANSCECHAPITRE
» Valeursetdonnéesentières
» Affectations
» Lesopérelsetlesopélogs
» Tournuresetrebouclages
equiintéressel'utilisateurd'unprogramme,cesontlesvaleursqueleprogrammecrée, triture,stocke, lit,envoie, reçoit.Cesvaleurs incarnentdesdonnées : texted'unepageWeb,pixelsd'uneimage,échantillond'unson,montantd'unsalairenet,
vitessed'unavion,etc.Ellessontextrêmementprécieuses,etdanscertainsdomainesvitales,commeenmédecineouenaéronautique.
Programmer suppose donc de bien savoir interpréter les valeurs pour pouvoir lessurveilleretlesfaireévoluerintelligemment.
Valeur : vient du latin valere, être puissant, une notion positive, sur quoi on peutcompter(danstouslessens).Unnombrel'estpardéfinition.C'estdoncunevaleur.
Donnée : représentation numérique d’une information selon des conventions quipermettentdetraitercetteinformationdefaçonsensée.
Dans ledébutdecechapitre,nousallonsvoircommentpasserdes simples signauxélectriquesbinairesquesontlesvaleursàdevéritablesdonnéesquiontdusenspourleshumains(etpourlesautresordinateursquiveulentdialogueraveclevôtre!).
Le mode d'écriture de ce premier chapitre est linéaire : nous écrivons des lignescommepournos texteshumainset leprogrammeréalisera lesactionsdans lemêmeordre,delapremièreligneàladernière.Danslechapitresuivant,nousdécouvrironscommentbrisercettemonotonie.
Valeursetespacemémoire
Nous avons vu dans la partie précédente que le processeur ne connaissait que dessuitesdevaleursbinaires0et1.Cefluxestdécoupéenunitésdehuitbits,quel'onnommedesoctets.
Tout processeur se caractérise par une largeur de mot machine, qui est sa largeurnaturelle.Elledétermineleplusgrandnombreentierpositif(sanssigne)quipeutêtrelu,écritouproduitparcalculenuneseuleopérationélémentaire.
Le peintre franco-polonais Roman Opalka (1931-2011) avait décidé d'écrire desnombresdeplusenplusgrandssurses toilessuccessives.Ilsavaitquelasuitedesnombresentiersétaitinfiniealorsquesavienel'étaitpas.
Dans la décennie 2010, la plupart des ordinateurs utilisent un processeur 32 ou64bits.Autrementdit,ilsgèrentenuneseuleopérationunpaquetdequatrefoishuitou de huit fois huit bits. C'est la largeur « naturelle » . Néanmoins, tous lesprocesseurs savent traiter individuellement des paquets de taille inférieure à cettelargeur,jusqu'àl'octet.
Les largeurs de valeurs numériques binaires qui peuvent être manipulées dans unprogrammesonttoujoursdesmultiplesdel'octetetdesmultipleslesunsdesautres:
» unoctet(8bits);
» deuxoctets(16bits);
» quatreoctets(32bits);
» huitoctets(64bits);
» (plusrarement)seizeoctets(128bits).
Leseulcasparticulier,maisnousn'enparleronspasplus,est le format scientifiqueétenduquicorrespondà80bits,soitdixoctets.Iln'estutiliséqueparlecoprocesseurarithmétiquepourlescalculsscientifiques.
FIGURE7.1:Formatsdevaleursbinaires.
Ces«récipientsàvaleur»sonttoutcedontdisposematériellementleprogrammeurpour travailler. Il va déployer des trésors d'invention pour, au final, déplacer,dupliqueretmodifierdesvaleursbinairesdansl'undecesquelquesformats.
Lesvaleurssontdoncstockéesdans lamémoirede travailde l'ordinateurpourêtrelues, modifiées dans le processeur puis écrites dans la mémoire. Pour réussir cesopérations,leprocesseurdoitconnaîtretroiséléments:
» l'adressemémoiredelavaleuràlireouàécrire.C'estaussiune
valeurnumériquebinaire,maisquicirculesuruncanalélectrique
séparédesdonnées(lebusd'adresses);
» lenombred'unitésdontestconstituéchaquepaquetqu'il
manipule:unoctet,deux,quatreouhuit.Ilfautdoncune
conventionpourlatailledelavaleur;
» lanatureducontenuparmilestroisreprésentationspossibles
(entiernaturelpositif,entierrelatifpositif/négatifoubiennombre
décimalàvirguleflottante,commeindiquédanslapartie
précédente).
Pourêtreexact,leprocesseurn'aaucunmoyendesavoirsivousvoustrompezsurlanatureducontenu.C'estàvouslorsquevousécrivezvoslignesdecodesourcedenepasvoustromper.Pourleprocesseur,touteslessuitesde0etde1sevalent.
Pourrépondreàcetriplebesoin,deuxconceptsontétéinventés:celuidevariableetceluidetype.Ilssontintimementliés.
» Leconceptdevariablerépondaubesoindelocaliserefficacement
chaquevaleurenmémoire,c'est-à-diredel'identifier.C'estpourquoi
onparleaussid'identifiantpourunevariable.
» Leconceptdetyperépondauxdeuxautresbesoins.Ildéterminela
longueurenoctetsdelavaleuretlanaturedelavaleurqui
détermineàquoiellecorresponddanslemondehumainenbase
décimale.
Dans le processeur, les instructions machine gèrent les largeurs de données enmultiplesdel'octet.Pourdesraisonshistoriques,l'expressionWORDaétéconsacréechezIntelpourlegroupededeuxoctets(16bits).Lesautrestaillesensontdéduites:DW(DoubleWord)pour ledoublemot, soit32bits, etQWpour lequadruplemot(64bits).
Puisquelesdeuxconceptsvontdepair,commençonsparceluidetype.Nousverronslesvariablestrèsviteaprès.
LeconceptdetypededonnéesNousparlons icides typesélémentaires,carvousverrezdansunautrechapitredestypescomplexesquipermettentdegrouperdesvariables.
Lestypesélémentaires(ouatomiques)dulangageCsont:
» lestypesentiers,dontlechefdefilesenommeint(abréviation
deintegerouentier);
» lestypesdécimaux,ditsflottants,dontlechefdefilesenomme
float.
Lestypespourlesvaleursentières(int)Les valeurs entières correspondent à nos nombres entiers naturels (sans signe) etrelatifs(positifsounégatifs).
Lestypesentiersexistentendeuxvariantes:signéeetnonsignée.Lesentiersnaturelssontlasérie0,1,2,3jusqu'àl'infini.Lesentiersrelatifspossèdentunsignepositifounégatifindiquantleurpositionparrapportauzéro.Lesrelatifsnégatifssont-1,-2,-3,etc.
Les types entiers sont en général signés si vous ne spécifiez pas le contraire enajoutant unsigned avant le nom de type. Cela peut varier selon le modèle desystème d'exploitation et d'outil de programmation. En cas de doute, vous pouvezpréciseravecletermesignedavantlenomdetype.
Unedesresponsabilitésduprogrammeurestdebienchoisirsestypesdedonnées.S'ilchoisitsystématiquementletypeleplusspacieux,ilconsommedel'espacemémoireetralentit les opérations. S'il est trop avare, il prend le risque de faire déborder unevariablequicontiendraalorsunevaleurfausse(nousverronsdesexemplesplusloin).
Voyonsdonc lespossibilitésdes types entiers signésdans la configuration standard(PCàprocesseurIntelsériei,compilateurGNUC32bits):
Tableau7.1:TypesentiersdulangageC.
Nomdu
type
Occupation Valeurminimale Valeurmaximale
char 1octet -128 +127
short 2octets -32768 +32767
int 4octets -2147483648 +2147483647
long 4octets -2147483648 +2147483647
long
long8octets Environ-9milliardsde
milliards
Environ+9milliardsde
milliards
Non,cen'estpasuneerreur:letypelongéquivautengénéralau typeint,maispas sur tous les processeurs et compilateurs. SousMacOSX par exemple dans laconfigurationstandarddel'outildecréationXCode,letypelongoffre8octetsaulieude4,commesongrandfrèrelonglong.
Etvoicilespossibilitésdestypesentiersnonsignés(unsigned):
Tableau7.2:TypesentiersnonsignésdulangageC.
Nomdutype Occupation Valeur
minimale
Valeurmaximale
unsignedchar 1octet 0 255
unsignedshort 2octets 0 65535
unsignedint 4octets 0 4294967295
unsignedlong 4octets 0 4294967295
unsignedlong
long8octets 0 Environ+18milliardsde
milliards
Vous constatez que les variantes non signées offrent une plage de valeurs positivesdeuxfoisplusélevée,cequiestlogique.
Certainstypessontàgéométrievariable.Leurlargeurn'estpaslamêmesurtouteslesmachines,enfonctionduprocesseuretducompilateur.C'estsurtoutlecasdelongquipeutoccupersoit4,soit8octets.
Dans un ordinateur, lorsqu'il faut stocker les différents octets qui constituent unevaleur, il faut décider dans quel sens on les place dans les cases mémoiresuccessives.Les concepteurs des premiers ordinateurs travaillant pour des sociétés
concurrentes, ils n'ont pas cherché à se concerter. Certains ont choisi un ordre destockageetd'autresl'ordreinverse.
Supposonslavaleurpositiveentière258surdeuxoctets:
0000000100000010(l'espaceestajoutépourrendreletoutlisible)
ORDREDESTOCKAGEDESOCTETS(«ENDIANNESS»)
Imaginezquecertainespersonnes lisent lesnombresà l'envers.Quandvous
écrivez931euros, lapersonnecomprend139.Heureusement, tout lemonde
« sait » que dans un nombre à plusieurs chiffres, les unités sont écrites en
dernier,aveclesdizainesplusàgauche,puislescentaines,etc.
Maisvoussavezpeut-êtrequ'enallemandparexempleondit l'unitéavant la
dizaine:39sedit«neuf-et-trente».
Lesdeuxoctetsn'ontpaslemêmepoids(toutcommele3dans35vautdixfoisplusque le 5). Si on les comprend à l'envers, la valeur décimale n'est pas 258mais513(vérifiez!).
Ilyaunoctetau«grosbout»etunau«petitbout» .LesAnglaisparlentdebigendian etde littleendian. C'est le fabricant du processeur (le fondeur) qui décidedansquelsenslapucestockelesoctetsdesvaleurs.
Nousverrons lesfichiersd'en-têtedansunprochainchapitre.Celuinommé limits.hcontient les valeurs maximales utilisées par votre outil de construction (votrecompilateur).
Saufmention spéciale«unsigned» , les typesnumériques entiers sont toujourssignés.
LetypeentierdebaseintAvecunprocesseur32ou64bits,letypeintconsomme32bits,soitquatreoctets:
11111111111111111111111111111111
12345678123456781234567812345678
Leplusgrandnombre(entierpositif!)pouvantêtrereprésentéavec32bitsestégaleà la somme de toutes les puissances de deux jusqu'à 31 (on commence à deuxpuissancezéro,soitun).
Voicilesvaleursdechaquepuissancededeux,expriméesdansnotrebasedécimale:
Premieroctet:
1+2+4+8+16+32+64+128
Deuxièmeoctet:
+256+512+1024+2048+4096+8192+16384+32768
Troisièmeoctet:
+65536+131072+262144+524288
+1048576+2097152+4194304+8388608
Quatrièmeoctet:
+16777216+33554432+67108864+134217728
+268435456+536870912+1073741824+2147483648
Lasommedetoutescesvaleursdonne4294967295,soitunpeuplusde4milliards.Vousremarquezqueceplafondesttoujoursimpair.C'estnormalpuisquelebitayantlemoinsdepoids(lesunitésbinaires)estsoitzéro,soit1.Touslesautresbitsétantdes valeurs paires (multiples de deux), en ajoutant l'unité, on obtient un nombreimpair.
Cettesommede4milliardssuffitpourstockerlenombredemilliardairessurTerre,maispaspourmémoriser leur richesse ;nipourcompter lenombredeneuronesdel'humain le plus pauvre (20 milliards de neurones en moyenne dans le cortexet80milliardsentout).
Ce typeentierdebaseest trèsutilisé,mais iln'estpas leplusadaptédanscertainscas.
Lesvariantesdeint(char,short,long,longlong)La largeur « naturelle » est imposée par le matériel de la machine, mais lesprogrammeursontbesoindepouvoirréduirel'occupationmémoiredèsquepossible.
Supposezunprogrammequiproduit la sériedesmillenombres entiersde0 à999.Aveclataillenormaled'unprocesseur32bits,lestockagevaréclamer1000fois4,soit4000octets.
Le langage C propose un type prédéfini plus compact nomméshort (largeur de16bits).Endéclarantvosvariablesaveccetype(abréviationdeshortint,entier
court),votresériedenombresvaoccupermoitiémoinsdemémoire.
Inversement,pour stockerdesvaleursnumériquesplusgrandesque4294967296,vousdisposezd'untypeentiertrèslongquis'écritlonglongenC.Satailleestledoubledecelledel'entierdebase,donc64bits.
S'ilyaun typelonglong, il existebien sûrun typelong (non redoublé). Enthéorie,ildoitavoirunetailledoubledecelledeint,maisenpratiqueilestsouventdemêmetaille (32bits). Iln'estutileque lorsque le typeintne faitque2octets(16bits),carlongcorrespondà4octets.
MODÈLESDEDONNÉESMATÉRIELS
Surunemachineavecprocesseur64bits,letypedevaleurintestlaplupart
dutempsmaintenuà32bitspourqueleprogrammeuraittoutelapanoplieà
sadisposition(8,16,32,64).C'estlemodèlededonnéesLLP64.Ilyaeneffet
plusieursconventionsdemodèlesdedonnées:
LLP64:lestypesintetlongsur32bits.Le«LL»désigneletypelonglong
quiestsur64bitsdanstouslescas.C'estlemodèlecourantetceluisurlequel
nous nous basons. Le P signifie pointeur, le type spécial pour stocker une
adressemémoire.
LP64:letypelongetletypespécialpointeursontsur64bits.
ILP64:letypeintestaussisur64bits.
SILP64:mêmeletypeshortestsur64bitsenplusdestroisautres.
Troistypespourlesvaleursrationnelles(float)Les valeurs rationnelles correspondent à peu près à nos nombres fractionnaires(revoir la partie précédente).Ce sont les nombres àvirgule,mais apprenez tout desuite qu'en informatique, on utilise le point car c'est la convention anglaise pour leséparateurdécimal.
Lesrationnelssontgérésaveclestypesflottantsquisonttoujourssignés.
Tableau7.3:TypesflottantsdulangageC.
Nomdutype Empreinte Valeurminimale Valeurmaximale Précision
float 4octets 1.2E38 3.4E+38 6chiffres
double 8octets 2.3E-308 1.7E+308 15chiffres
longdouble 10octets 3.4E-4932 1.1E+4932 19chiffres
Il n'existe en langageC que ces huit formats de données physiques, cinq entiers ettroisflottants.
VotrepremièrevariableQuelquesoitletyped'unevaleur,ilfautpouvoirlastockerenmémoiredefaçonàlaretrouver. Ceci suppose de lui associer une variable. Le concept de variable estfondamental.Rappelonssesraisonsd'être:
1. Lenomdelavariablepermetdedésignerdefaçontextuelle
plutôtquenumériquel'adresseenmémoireoùeststockéeune
valeurnumérique.Ilestplusfaciled'employerunnomque
d'indiqueruneadressenumérique(dustyleFF3A28C1,carc'est
souventindiquéenhexadécimal).Cettedésignation
symboliquepermetenoutredelaisserl'adresseréellevarier
d'uneexécutionàl'autre.
2. Danspresquetousleslangagesdeprogrammation,et
notammentenlangageC,lorsquevousbaptisezunevariable
(celas'appelleladéclarationdelavariable),vousdevezen
mêmetempsdéciderdesontype(pourquelesystèmesache
combiendeplaceildoitréserverpourlavariable).
Variable : nomunique suggérant auprogrammeur et à ses collègues le contenud'unespace mémoire lié à ce nom et contenant une valeur pouvant varier au cours del’exécutionduprogramme.
Leschémasuivantillustreleconceptdevariable.
FIGURE7.2:Leconceptdevariable.
Voyonsd'abordlesrèglesàsuivrepourdonnerdesnomsàvosvariables.Nousdisonsbien vos variables, car c'est vous qui décidez. Nous verrons ensuite d'où peutprovenirlecontenudelavariable,savaleur.
Jeveuxdesnoms!Àpartirdecombiendechèvreslebergernepeutplusdonnerunprénomàchacune?Voiciundomaineoùl'informatiqueestplushumainequenosgrandséleveurs:quellequesoitlatailledevotretroupeaudevariables,chacunedevraavoirunnom.
Parmi lesmotsetsymboles,certainssont figés. Il faut lesécrire telsquels.Cesontquasiment toujoursdesmotsenanglaiscommewhile,printf(),case. On lesappelledesmotsréservésoumotsclés.
Pourtouslesautresmots,c'estvousquidécidez.Lesdeuxprincipauxtypesdemotsdont lenomestchoisi (presque) librementpar l'auteurduprogrammesont lesnomsdes variables et les noms des fonctions (nous verrons le concept de fonction lemomentvenu).
NomsdevariableetorthographeUnnomdevariableestunmot;commedansnoslangageshumains,unmotnecontientpasd'espace.Comprenezvouscettephrase?
Dansvosnomsdevariables,vouspouvezdéployervotrecréativité,maistoutdépenddesconditionsdanslesquellesvousprogrammez:
» Sivoustravaillezenéquipe,dansuneentrepriseouungroupede
programmeurssurunprojetdelogiciellibre,ilestconseillédese
mettred'accordsurdesconventionsdenommage.
» Sivoustravaillezseul,vouspouvezdanslefeudel'actionchoisir
vosnomsàlavolée,maisvousserezraviplustardd'avoirappliqué
unprincipe.
Voicidesnomsdevariablesacceptésdanslamajoritédeslangages:
x
mavar2
trucbidule
num_Secu
VitesseMaxLumi
LescontraintesdenommagePourchoisirvosnomsdevariables,vousavezdesdevoirsetdespouvoirs:
» Vousdevezrespecterdesrèglespropresaulangage.
» Vouspouvezadopterdesconventionsdemeilleurelisibilité.
SelonlesrèglesdulangageCetdenombreuxautres,vouspouvezutiliserseulement:
» les26lettresdel'alphabetanglaisenminuscules(aàz);
» les26lettresdel'alphabetanglaisenmajuscules(AàZ);
» lesdixchiffres0à9et;
» lecaractèredesoulignement(_).
Lenomnedoitjamaiscommencerparunchiffreetilestfortementdéconseillédelefairecommencerparlesouligné.
Enpremièreapproche,considérezqu'ilestimpossiblededonnerlemêmenomàdeuxvariables.
En conséquence de ces règles, les programmeurs francophones (et tous ceux quipréfèrent ne pas donner des noms anglais à leurs identifiants) doiventmuseler leurardeur,carleslettresaccentuéessontinterdites.
BienchoisirsesnomsPourquelesnomsrestentsuggestifslorsquevousserezàlatêtedetoutunchepteldevariables,ilestconseillédelesconstruireàpartirdestermessignificatifs.
Sinousavonsparexemplebesoind'unevariabledestinéeàcontenir le salairebrutmensuel d'un salarié et d'une autre pour le salaire net à payer, nous pourrons lesnommer:
SalaireBrut
SalaireNetAP
Cette technique rend les noms plus lisibles qu'en écrivant salairebrut etsalairenetap. Certains préfèrent utiliser le souligné, comme danssalaire_brut et salaire_net_ap, mais la majorité des programmeursprivilégientl'écritureendosdechameau.Lesanglaisparlentd'écritureCamelCase:
DosDeChameau
DéclarezvosvariablesPourquoifaut-ildéclarerunevariable?Pourqueleprogrammeexécutableréserveunespacemémoirepourstockerlavaleur.
Prenonslecasd'unevariablepourmémoriserlenombred'heurestravailléesdansunesemaine.Mêmedansuncasaussisimple,leprogrammeurdoitimaginerquelleseraàpeuprèslavaleurmaximalequ'ilfaudrapouvoirstockerdanslavariablequirecevralerésultat.
Dans l'exemple, le plus petit type entier conviendra, car peu de personnes sontautorisées à travailler plus de 127 heures par semaine. (Nous nous interdisons lesfractionsd'heurespourl'instant.)
Choisissonsdoncletypechar.Variantesignéeounonsignée?Quandonneprécisepas, c'est engénéralsigné pour tous les typesentiers, sauf justement lepetitcharquiestsouventnonsigné,sansdoutepourdonnerunpeud'ouvertureàl'internationaldulangageC.
L'alphabet (lettres majuscules et minuscules) dont on dispose lorsque seuls 7 bitsserventàcoderlescaractèresestlimitéauxvingt-sixlettresdel'anglais.Nosaccentsetcédillesrequièrentl'utilisationduhuitièmebitquinepeutdoncpasservirenmêmetempsdesignenégatif.
C'estétonnant,maisà ladifférencede laplupartdes livresdeprogrammation,nousosons utiliser le petit type char pour des nombres. Il aurait pu s'appeler byte(octet),maiscommeilsertsurtoutpourlesmessagesdanslesprogrammesanglais,ilaétébaptiséchar.NousreviendronssurcetimportantsujetàlafinduChapitre10.
Pour le nom, nous tenons compte des règles indiquées un peu plus haut. Voiciplusieurspossibilités:
h
heurestravailleessemaine
heures_par_ssemaine
hSem
Le nomdoit être suggestif.Quand vous aurez vingt variables, chacune devra resterfacile à distinguer. Il faut donc une certaine longueur, mais pas trop. Un nom devariableinutilementlongadeuxinconvénients:
» C'estpluslongàsaisir(unprogrammeurestunécrivainpourdes
lecteursautomates,maisilfautbienécrireles«mots»).
» Celafaitdéborderplusdelignesdelalargeurd'affichageàl'écran
etàl'impression,cequin'estpasgravemaisjoyeusementévitable.
PourquoipascHeuresHebdo?Lalettrecenpréfixeestpratiquepoursuggérerletypededonnée.
Nous avons le type et le nom, voici donc notre première déclaration de variableofficielleetreconnuecommevalidepartouslesprogrammeursCdumonde:
charcHeuresHebdo;
Etvoilà,c'estdéjàfini.Unefoiscettelignepasséedansletextesource, lavariablepeutêtreutilisée.Elleestenquelquesorte«vivante»etleresterajusqu'àlafinduprogrammeousous-programmedanslaquellenousavonsplacésadéclaration.
Si lavariableexiste,c'estqu'ellevaêtreassociéeàunevaleur (c'était lebutdesamise aumonde). Pour l'instant, ce qu'elle contient est soit la valeur zéro, soit sansaucunesignification.Considérezquelecontenunevautriendanscetétatinitial.
En revanche, la variable correspond déjà à une adresse mémoire qui est celle dupremier octet où la valeur sera stockée (ici, c'est le seul octet, puisquenous avonschoisichar).
Sinousajoutonsdesactionsàunminusculeprogrammedéclarantcettevariable,nouspouvonsafficheràl'écranlavaleuretl'adresse.Ilestbientroptôtpourprésenterlafonctiond'affichage(c'estprintf()).Voicidoncdespseudo-instructions:
ActionAffichage(cHeuresHebdo);
ActionAffichage(&cHeuresHebdo);
Unefoisquel'ordinateuraexécutécesdeuxactions,onvoitceciàl'écran:
0
28FF1F
Le premier nombre est la valeur qui est ici 0. Certains outils de génération del'exécutable(«compilateurs»)écriventd'officelavaleur0danstouteslesvariableslorsqu'ilslesimplantent;d'autresnelefontpasetlaissentaudépartlavaleurquisetrouvaitàcetendroitàcemoment.
Rappelonsquel'espacemémoireestsanscesserecyclé:unprogrammeenutiliseuneportionpuissetermineetrestituel'espace.Quandunautreprogrammeleréutilise,lesvaleursdel'ancienprogrammesonttoujoursprésentesenattendantd'être«écrasées».Certainspiratesseserventdecestraces.
Le second nombre est l'adressemémoire. Nous l'avons fait afficher en base 16 ouhexadécimal(endécimalcelacorrespondà2686751).
&POURÉPIERL'ADRESSE
Lapossibilitédeconnaîtrel'adressedestockaged'unevariableestengénéral
considéréecommeunconceptbientropdifficilepourlesdébutants.Nousne
sommes pas de cet avis. En stockant cette adresse dans une variable d'un
genrespécial(unpointeur),onpeutensuiteaccéderàlavaleursansconnaître
lenomde la variable.C'est trèspratiqueet indispensabledans certains cas,
commenousleverronsdansd'autreschapitres.
L'utilisation impropredespointeurs est effectivement fatale, unpeu comme
uncaristecomplètementivrepromenantsonengindansunentrepôt.Imposez
l'alcootestàlaprisedeservice!
Retenez que le & collé avant le nom d'une variable permet d'obtenir son
adresseaulieudesoncontenu.
VariablesnonentièresL'exemple suivant calcule une température en degrés Fahrenheit à partir de celleindiquéeendegrésCelsius:
LISTING7.1ExtraitdutextesourceCelsFahr.c
//CelsFahr.c
floatcels=37.2;
floatfahr=0.0;
//Variablecelsiusinitiale=37.200001
fahr=cels*1.8;
//Variablefahrapres*1.8=66.959999
fahr=fahr+32;
//Variablefahrapresajoutde32=98.959999
Les imprécisions du résultat découlent de la façon dont sont codées les valeurs àvirgule.Endehorsdecette remarque, lesvaleursnonentières s'utilisent comme lesvaleursentières.
Nousavonsvudans lapartieprécédentequecequi se trouveaprès lavirguleétaitdécomposéenpuissancenégativesdedeux.
Lavaleur1.25peutêtre stockée sansperte, car .25vaut1/8dedeux,mais1.24nepeut pas l'être. La valeur la plus proche en simple précision (float) est1.2400000095367431640625.
Originespossiblesd'unevaleurD'oùpeutprovenirlavaleurquenousvoulonsstockerdansnotrevariable?
1. VouspouvezindiquerdanslecodesourceuneValeur
NumériqueLittérale(nousabrégeronsenVNL),comme35,
48900ou37.2.
2. Lavaleurpeutêtrelerésultatdel'évaluationd'uneexpression
comme(2+(3*12)).
3. Ellepeutêtrelerésultatdutravaild'unsous-programmequi
renvoiecettevaleurparreturn.Cesous-programmepeut
l'avoirobtenuedenombreusesmanières:
· endemandantàl'utilisateurdelasaisirauclavier;
· enlaréceptionnantdansunfluxdedonnéesdepuisunfichier
surdisqueouunserveurWeb;
· enlagénérantàpartird'autresvaleurs.
Unopérateurestunsymbolecourtquireprésenteuneaction,unefonction.L'opérateurd'affectationfaitunecopied'unevaleurversunlieudestockage.
Dans ce chapitre, nous nous limitons aux deux premières origines : lesVNL et lesexpressions.
Lesvaleursnumériqueslittérales(VNLe)Commesonnomlesuggère,lavaleurestdanscecaslittéralementfixée.Ellenepeutvarier.Sionl'écritdansunevariablequiaprioridevraitvarier,c'estengénéralpourluidonnerunevaleurdedépart,initiale.
BasesdenotationIlestfortpratiquequel'onpuisseindiquerlesvaleursnumériquesennotationhumainehabituelle,c'est-à-direenbase10.Rappelonslestroisautresbasespossibles:
» Labase2;trèsrarementutilisée,carilestmalcommoded'écrire
dessuitesde0etde1.Certainesopérationsconcernantles
masquesdebitss'enservent.
» Labase16ouhexadécimale;cettebaseesttrèspratiqueetsert
souventàindiquerdesvaleursdanslesprojetstrèstechniques.Elle
utiliseleschiffresde0à9puisleslettresdeAàF.
» Labase8ouoctale;peuutiliséedenosjours,ellen'utilisequeles
chiffresde0à7.
PourexprimeruneVNLenhexadécimal,ilfautajouterlepréfixe0x(zérox)commececi:
0xFF14
Vousn'utiliserezsansdoute jamais lesVNLenoctal,mais ilestessentieldesavoirque si vous faites commencervotrevaleurpar le chiffre0, il est considéré commeexpriméenoctal,carle0sertdepréfixeàlabaseoctale:
0322
Parexemple,écrire0849estrefusé,puisqu'enoctaliln'yapasdechiffre8et9.Laleçon à en tirer est qu'il ne faut jamais commencervosVNLentièrespar le chiffrezéro(ilestd'ailleursinutiledanscecas).
Nousverronsplusloinquedèsqu'unpointséparateurestdétecté,leproblèmenesepose plus. Dans ce cas, c'est une valeur numérique non entière (avec des chiffresderrièrelavirgule)etcegenredevaleurnes'écritjamaisenoctal.
Enbase10,vouspouvezécriredesVNLpositivessansindiquerlesigne,maisilfautlesignepourlesvaleursnégatives:
3690
-47
ValeursnumériqueslittéralesflottantesPourécrireunevaleurnumériquelittéraleflottantedanslecodesource,vousavezlechoixentredeuxformats:
» Soitvousécrivezlavaleuravecauminimumunpoint:
1.30
0.45
.45
990.50
12.
-2.0098
Silavaleurestnonentière,onutiliselepoint,paslavirgule.
Sivousindiquezunevirgule,lecodesourceserarefusé,carla
virgulesertdeséparateurentreéléments.
» Soitvousutilisezlanotationscientifique,maisnousn'enabuserons
pasdanscelivred'initiation.LeEcorrespondàl'exposant:
1.175494E-38
3.402823E+38
Cesdeuxvaleurssontpositives!Lapremièreesttrèspetite,carc'estl'exposantquiestnégatifici.
Voicideuxnombresflottantsnégatifs:
-1.175494E-38
-3.402823E+38
Voyons maintenant comment stocker la valeur désirée dans la variable. Il suffitd'écrireuneinstructioncitantlenomdelavariable.
Leconceptd'instructionEn langage C, une instruction est un ou plusieurs mots correctement agencéscomportant endernier un signepoint-virgule quimarque la fin de l'instruction.Uneinstruction représente une action réelle. Voici le format schématique (le nombred'élémentsetlanaturedechacunpeuventvarier):
element1element2element3;
Une instruction se termine (presque) toujours par un signe point-virgule qui sert demarqueurdefind'instruction.
L'oubli du marqueur de fin est une étourderie classique des débutants enprogrammation.Un des rares langages parmi les plus usités qui ne réclame pas demarqueurdefind'instructionsenommePython.
Uneinstructionpourstockerlavaleur(=)
Lapremière instructionqu'il faut découvrir est celle qui sert à écrire (stocker) unevaleurdansunevariable,c'est-à-direàluiaffecterunevaleur.
C'est l'instructiondited'affectation.Ellese fondesurunsymboled'égalité=quiestl'opérateurd'affectation.Elleréaliseuneaction(c'estuneinstruction):copierdanslavariable indiquée sur sa gauche la valeur indiquée sur sa droite (ou la valeur quirésultedel'évaluationdel'expressionsursadroite).
FIGURE7.3:Schémadestockaged'unevaleurentière.
Unopérateurestunsymbolecourtquireprésenteuneaction,unefonction.L'opérateurd'affectationfaitunecopied'unevaleurversunlieudestockage.
Tous les langages n'utilisent pas le symbole = pour l'opérateur d'affectation, car ilentraînedesconfusions,mêmechezlesprogrammeursCexpérimentés.Eneffet,pourcomparerdeuxvaleurs, ilfaututiliser lesymboleredoublé(==).Nousverronsceladanslechapitresurlesexpressionsconditionnelles.
POURQUOIUNSIGNED'ÉGALITÉ?
Dans les années 1960, le prédécesseur du langageC, le langageBCPL, avait
choisilecoupledesignes:=pourl'opérateurd'affectation.Pouruneraison
mystérieuse, le C l'a abrégé en signe égal isolé. Bien des programmeurs se
trompenttous les joursenécrivantdesexpressionsdecomparaisonavecce
signe,carc'estainsiquel'onécritenlanguehumaine(SImaVar=5).Mais
pourcomparerenC,ilfaututiliserdeuxsigneségalàlasuite:SImaVar==
3.LeslangagesinspirésduCcommeJavaetC#ontrepriscechoixétrange.
Exemplesd'affectationsReprenonsnotrevariablecHeuresHebdoetattribuons-luiuneVNLquiserviradevaleurinitiale:
cHeuresHebdo=39;
Remarquezquenousn'indiquonsplusletypeenpréfixedunom.Unefoissuffit.
Quesepasse-t-il sinousnous tromponsdans l'écriturede laVNL?EssayonsavecuneVNLf(flottantounombrerationnel)comme39.99:
cHeuresHebdo=39.99;
C'est étrangement accepté, ou plutôt, c'est ignoré par l'implacable vérificateur quigénère le code exécutable. La valeur stockée reste 39. Il n'y a pas d'arrondi. Leschiffres inconvenants pour une valeur entière sont ignorés. Il n'y a pas non pluschangementd'officedutypedelavariabledeintversfloat.Etsurtout, iln'yaaucunmessaged'avertissementpendant lacompilationquisedéroulesansproblèmeapparent.
Cen'estpasgrave,puisquec'estvousquiêtesincohérent:vousdéclarezunevariabledetypeentier,puisvousproposezd'ystockerunevaleurnonentière!Tantpispourvous.
Sachezqu'ilexistedestroncaturesautomatiquesdetypesentiers:nousverronsplusloin que ce genre de changement de type se produit dans certains cas et que c'estparfoissouhaité.Celas'appelleuntranstypage.
UnetentativededébordementEssayonsmaintenant de faire craquer notre variable ou plutôt la casemémoire quireçoitsavaleur:
cHeuresHebdo=260;
Puisque nous avons choisi la variante non signée du type char, nous pouvons ystockerunevaleurentre0et255. Ilyadoncunpetitproblème.Nousavons8bitspourcoderlavaleuretonnousdemanded'ystockerunevaleurquirequiert9bits.
Analysonslasituationsurpapierlibre(pasdanslecodesource).Nousregrouponslesbitspar4pouraméliorerlalisibilité:
Pourlavaleur256,lebit9à1ettouslesautresà0soit:
100000000
Mais on ne peut pas gérer une portion d'octet. Comme chez les loueurs, tout octetcommencéestdû!Nousécrivonsdonc:
0000000100000000
Notrevaleur260vaut256+4,doncnouscodonslavaleurdécimale4dansl'octetdedroite:
0000000100000100
Commentlecompilateurva-t-ils'ensortir?Ilvaseplaindreenaffichantceci:
Numérodelignesource:warning:overflowinimplicit
constantconversion
Lesmessagesdecompilationsontrarementtraduits.Celui-cisignifie:
Attention!Débordementdansuneconversionimplicitede
constante.
Votrevaleurnumériquelittéraleestfigée.C'estdoncunevaleurconstante.LacibledelacopieestdetypecharalorsquelaVNL,auvudesavaleur,estauminimumdutype correspondant à la taille immédiatement supérieure (le typeshort sur deuxoctets).Maisonl'obligeàtenirdansunseuloctet!
Enfait,lecompilateurfaitcequ'ilpeut.Voicilavaleurqu'ilvademanderdestockerdansvotrevariable:
4
Oui,seulement4,lecontenudel'octetdepoidsfaible.Cen'étaitpasvotreintention.On aurait pu imaginer que le compilateur décide de stocker la valeur maximalepossible(255)oud'arrêtersuruneerreur.Non, ilacceptedevoustrahir,pourvouspunird'écrireunebêtise.
Denombreuxprogrammeurssonttropimpatientsdefairemarcherleursprogrammes.Ils résolvent les erreurs de compilation, parce qu'ils sont bien obligés (en casd'erreur, le programme exécutable n'est pas généré, donc il n'y a rien à tester). Parimpatience, ils négligent les avertissements, ce qui peut entraîner des erreurs delogiquedifficilesàdétecteretcorriger.Vousaurezcomprisqu'ilnefautpaslesimiter.
Ceraisonnementestapplicableauxautrestypesentiersetflottants.
sizeof()pourfairelepoint
Vous disposez d'un opérateur spécial nommésizeof qui permet de connaître lenombred'octetsoccupésparunevariable.Ils'utiliseenpréfixedunomdutypeoudunomdevariable:
sizeof(int)
sizeof(nomVariable)
Puisquec'estuneexpression,ilfautenrécupérerlavaleurdansunevariable,commececi:
laTaille=sizeof(nomVariable);
Voici les réponsesdonnéesavecunprocesseur i7et lecompilateurGNUC32bitssousWindows:
//Empreintememoired'unchar:1
//Empreintememoired'unshort:2
//Empreintememoired'unint:4
//Empreintememoired'unlong:4
//Empreintememoired'unlonglong:8
//Empreintememoired'unfloat:4
//Empreintememoired'undouble:8
//Empreintememoired'unpointeur:4
Elleexiste?Utilisez-la!Une fois qu'une variable est déclarée, le simple fait de citer son nom équivaut àindiquerlavaleurqu'ellepossèdeàcemoment.Biensûr,celan'ad'intérêtqu'unefoisquelavariableareçuunepremièrevaleur.
Voiciunexemplededéclarationsuiviededeuxutilisations:
charcHeuresHebdo;
intiNouvelle;
cHeuresHebdo=10;
iNouvelle=cHeuresHebdo;
cHeuresHebdo=25;
Une fois la quatrième ligne (instruction) exécutée, la nouvelle variable contient lamême valeur que l'autre (10). Le contenu de cHeuresHebdo est modifié justeaprès.
Vousremarquezquenousstockonsdansunevariabledetypeintunevaleurluedansunevariabledepluspetite taille.Dansce sens, celaneposepasproblème, sauf sic'estuneerreuretquevousvoulezensuiteécrire lecontenudeiNouvelledansunevariablemoinsspacieusecommecHeuresHebdo.Celaneseracorrectquesila valeur reste dans les limites acceptables par la destination. Il faut respecter lestypes!
DestypesquiserespectentComme l'amontré l'exemple précédent, il faut rester cohérent dans l'utilisation desvariables.Demandonsdestockerunevariablefloatdansunevariableentière:
unsignedcharcu=0;
floatf=39.9999;
cu=f;
Lerésultatseraégalà:
39
Iln'yapasd'arrondi,maistroncature.Seulelapartieentièreestpriseencompte.
LecasdutypecharNon,lenomdutypecharn'arienàvoiraveclemotutiliséparlesQuébécoispour« voiture » . C'est l'abréviation dumot anglais character qui signifie acteur, maisaussiplussimplementcaractère.Etnoussavonstouscequ'estuncaractère.Oupas?
Uncaractèreestunereprésentationvisuelle,undessin,d'unélémentd'écriture(lettre,chiffre,accent,symbole).Onparleaussideglyphe.Leprocesseurn'aaucuneidéedece que c'est. En revanche, le circuit vidéo qui gère les affichages dispose d'unemémoiredanslaquelleuntableauassurelescorrespondancesentrelesdessinsetlesvaleursnumériquesbinaires.
Comme les pionniers en informatique sont de langue anglaise, ils ont pu se suffired'une centaine de valeurs numériques pour écrire dans leur langue. Et pour unecentainedevaleurs(jeudecaractèresASCIIdebase),lapluspetiteunitédestockage
suffit largement,mêmedans sa variante signée (de0 à 127, il n'y a pas devaleursnégativespourlescaractères).
Voilà pourquoi ce qui aurait dû s'appeler octet ou à la rigueur byte (l'équivalentanglaispourungroupedehuitbits)estdevenuchar.
Dans ce qui précède, nous avons volontairement utilisé ce type pour des valeursnumériquesaptesàservirdansdescalculsenignorantlarelationaveclescaractèresaffichés.Eneffet,cetterelationintimeestévidentepourunAméricain,maisbeaucoupmoins pour un Français et absolument plus pour un Oriental qui connaîtses4000 idéogrammessur leboutdesdoigts.CevastesujetseradébattuenfindeChapitre10.Souvenez-vousdedeuxmotsmagiques:UnicodeetUTF-8.Pourplusdeconfort,leslettresdelalangueanglaisepeuventêtreindiquéesnaturellementdanslecode source en tant quevaleurs littérales (et littéraires, pour le coup ! ).Voici uneaffectation valable pour notre variable. Nous avons choisi le a minuscule quicorrespondaucodenumérique97(endécimal):
cHeuresHebdo='a';
Sivousêtesétonnéparcequiestréellementstockédanslavariable,veuillezrelirelentementlesparagraphesprécédents.Voicicequieststocké:
97
Etriend'autre.Ilsetrouvequ'ilexistedanslafonctiond'affichageunmodeparticulier(ils'écrit%c,maisnousverronscelaplustard)quiaulieud'affichersuccessivementlesdeuxdessinsdeschiffresdelavaleur(ici,9et7)affichelecaractèredont97estlecode.Celapermetderetrouvernotreaminusculeàl'écran.
Rien n'empêche de demander d'afficher avec cette technique une valeur sans aucunrapport avec l'alphabet anglais, comme 8192. L'affichage n'a aucun sens, maisl'ordinateurn'enestpasgêné.Cesontdesoctets,etc'estcequ'ilaime.
Vous connaissez l'expression « Arrête ton char ! » . Elle pourra servir de moyenmnémotechnique pour ne jamais oublier que lorsque vous définissez une série decaractères(unechaîne),ilfautajouteràlafinuncaractèred'arrêtdevaleurzéro(c'estlezéroterminal).NousyreviendronsdansleChapitre10consacréauxtableaux.
Après les valeurs littérales, montons en puissance en abordant le conceptd'expression.
ExpressionslibresAprès la variable et l'opération d'affectation, l'expression est le troisième conceptessentielenprogrammation.C'estuneimportanteoriginepossiblepourunevaleur.
VoiciuneexpressiontrèssimpleenlangageC:
5+2;
Laplupartdeslangagesnetiennentpascomptedupassageàlalignesuivante.Nousaurionspuécrirececi,quiauraitétéaccepté:
5
+
2
;
Note:Dans cet exemple, cette répartitionn'a qu'un intérêt pédagogique,mais danscertaines instructions complexes, il est parfois utile d'augmenter la lisibilité enrépartissantsesélémentssurplusieurslignes.
Notreéquation5+2est suffisamment simplepourpouvoir être exécutéedirectementparlapartiematérielledel'ordinateur.Nousavonsvudanslapartieprécédentequele processeur (CPU) avait des capacités de calcul élémentaires. Il sait notammentfairel'additiondedeuxnombresentiersgrâceàsoninstructionmachineADD.
Danscetteopération,nousdistinguons:
» unopérateur(lesigne+);
» deuxopérandes(lesdeuxnombres).
L'ensembleformeuntoutquidoitêtrecohérent:c'estuneexpressionvalide.
ExpressionsinvalidesL'expressionsuivanten'estpasvalide(nipourunemachine,nipourunhumain):
5+;
Il manque quelque chose ! Par principe, l'opérateur d'addition + combine deuxopérandes,unàgaucheetl'autreàdroite.
Touteexpressionestfaitepourêtreévaluée.Cetravaild'évaluationdonneunrésultat,etcerésultatprendeffetàl'endroitoùestécritel'expression.
Expression ➩ Évaluation ➩ Résultatnumérique
OpérateursarithmétiquesLesopérateurssontdessymbolessurlesquelstoutlemondes'estmisd'accord.Danslesinfo-langages,unefamilled'opérateurstrèsutiliséeestcellequicorrespondàpeuprès à ceux de l'arithmétique classique : addition, multiplication, soustraction,divisionetreste.
Opérateur:symbolesurunoudeuxcaractèresd'uneactionquis'appliqueàun,deuxoutroisopérandes.
Voicilescinqopérateursarithmétiques:
Tableau7.4:OpérateursarithmétiquesdulangageC(opériths).
Opérateur Effet
+ Addition
* Multiplication(lesymbolecroixhabitueln'étaitpasprévudansle
jeudecaractèresdespremiersordinateurs)
- Soustraction(cesignesertaussiàmarquerlesvaleursnégatives)
/ Division(d'autressymbolesexistent,maisilsn'étaientpasprévus
nonplussurlespremiersordinateurs)
% Uneexpressioncentréeautourdel'opérateur«modulo»donne
commerésultatleresteentierd'unedivisionentredeuxnombres
entiers
OpérateursàdoubleusagePlusieursdecessymbolesserventàdeuxusagestrèsdifférents.C'estlecontextequipermetdedistinguerentreunesignificationetl'autre.
» L'opérateurd'addition+peutêtreindiquédevantunevaleurisolée
pourservirdesignepositif(rare).
» L'opérateurdesoustraction-peutêtreindiquédevantunevaleur
isoléepourservirdesignenégatif.
» L'opérateurdemultiplication*estsouventutilisédansuntout
autresenspourdéclarerunevariablepointeur(nousenparlerons
dansunautrechapitre)etpourrécupérerlavaleurpointéeparun
pointeur.
» Enfin,l'opérateurmodulo%sertdepréfixedeformatpourles
fonctionsstandarddelectureetd'écritureprintf()etscanf()
présentéesellesaussibienplusloin.
C'estenfonctiondecequel'analyseurdétecteàgaucheetàdroitedel'opérateurqu'ildécidedusensqu'ildoit luidonner.Parexemple,s'ilyaunopérandeàgaucheetàdroite du signe *, c'est une multiplication. Sinon, c'est l'usage en rapport avec unpointeur.
Lecodemachined'uneexpressionVoiciuneversionschématiqueducodemachine(enréalité,c'estpluscomplexe,carlesvaleurssontd'abordstockéesdansdeuxregistresduprocesseurpuisl'instructionADDs'appliqueaucontenudesregistres).
ADD5,2
Chaqueinstructionmachinecorrespondàuncodenumériquesur8bits,sonOpcode.SupposonsqueceluideADDsoit21(enbase16!).Nousavonsapprisdanslapartieprécédenteàconvertirentrebasesnumériques:
» 21enbase16,c'estdeuxseizaines+un,donc33enbase10;
» 33enbase10,c'est32+1,donc2puissance5(soit32)
+2puissance0(soit1);
» surunoctet,nesontà1quelesbits6et1(lebit1estceluileplusà
droite),cequidonne00100001.
» Procédonsdemêmepourlesdeuxnombres:
» 5endécimals'écrit00000101et
» 2endécimals'écrit00000010.
Lecodeexécutabledenotreéquationcomporteraittroisoctetsetpourraitressembleràceci:
001000010000010100000010
Unefoisqueleprocesseurauraexécutécetteinstruction,ilcontiendralerésultat(7)quelquepartsousformed'étatsélectriquesdansdusilicium…Maiscommentcapterlavaleurrésultantepourlaréutiliser?
ExpressionsetaffectationNous avons dit que l'expression était une source de valeur. Il est donc autoriséd'indiquer l'expression comme membre droit d'une instruction d'affectation à unevariable.Noussavonsdéjàcommentfaire:
cHeuresHebdo=(5+2);
(Pourquelalecturesoitaisée,nousajoutonsdesparenthèsesautourdel'expression.)
Iln'yaqu'uneligne,maisdeuxopérations:
1. L'expression5+2estévaluée.Lerésultatvient«prendresa
place».
2. Cerésultat(7)estcopiédanslacible,notrevariablegrâceà
l'opérateurdecopiedevaleur=quenousconnaissonsdéjà.
FIGURE7.4:Évaluationd'uneexpressionpuisstockagedurésultat.
ExpressionscomplexesLescinqopérateursarithmétiquesfonctionnentavecunopérandeàgaucheetunautreàdroite:
valeur1OPvaleur2
Rien ne vous interdit de combiner des opérateurs, ce qui aboutit à deux sous-expressions:
30+4*3
Cetteécriturepeutposerproblème.Lerésultatdel'expressionest-il112(34*3)oubien42(30+12)?
Le langage s'en sort en imposant des priorités différentes selon les opérateurs. Lamultiplicationestprioritairesurl'addition,donclerésultatseraici42.
Mais il est toujours préférable d'éviter ce genre de jeu de devinette. Pour ne pasdevoirmémoriserlesrèglesdepriorité(ilyabeaucoupd'opérateurs!),lasolutionestradicale:ajoutezdesparenthèses.
DesparenthèsespourclarifierEn délimitant les sous-expressions par des couples de parenthèses, vous indiquezexactementcequevousvoulezfairecalculer:
(30+4)*3
donnera112etnon42,encontrecarrantlacompréhensionpardéfautdel'analyseurdecode.Cequiestentreparenthèsesestévaluéd'abord.Unautreexemple:
30+4*4+3*2
estdifficileàinterpréter.Voicicommenttoutclarifier:
(30+4)*(4+(3*2))
Ilyaquatreévaluationsuccessives:
(3*2)
devient6.Lasuitedevient:
(30+4)*(4+6)
Lesdeuxsous-expressionsdonnent34et10.L'étapefinales'écrit:
34*10
L'évaluationfinaleaboutitàlavaleur340.Sansparenthèses,lesmultiplicationsétantprioritaires,c'estceciquiauraitétécomprisetcalculé:
30+(4*4)+(3*2))
Ce qui donne 52 et non 340. Ce n'est pas un détail. Ne soyez donc pas avare deparenthèsesdanslesexpressions.
QuandladivisionnetombepasjusteQuandvousdivisezunentierparunautre,silerésultatnetombepasjuste,ilestfaux(sansjeudemots):
(3/2)
donne:
1(avecunrestede1)
Partonsdel'exemplepluscompletsuivant:
LISTING7.2Extraitdutextesourcedivisent.c
//divisent.c
chardividende,diviseur,quotient;
dividende=9;
diviseur=5;
quotient=dividende/diviseur;
Lavariablequotientcontiendralavaleurentière4,alorsque9divisépar5estégalà1.8.
Unesolutionserait-ellededemanderdestockerlerésultatdansunnombredécimaldetypefloat:
chardividende,diviseur,quotient;
floatfquot;
dividende=9;
diviseur=5;
fquot=dividende/diviseur;
Peineperdue.Bienquelerécepteuraccepteunevaleurfractionnaire,lavaleurfquotvarecevoir1.000000,pas1.80000.
La solution radicaleconsisteà adopterdès ledépart le typefloatpour tous lescalculsquisupposentdesdivisions.
Parfois, vous devez travailler à partir de valeurs que vous recevez en l'état. Vousn'avez donc pas pu décider de leur type. Une technique d'appoint consiste alors àforcerlechangementdetype(transtypage).
Dans notre exemple, il suffit d'ajouter un nom de type en préfixe entre parenthèsesavantaumoinsunedesdeuxvaleursentièrespourquetoutlecalculbasculeverslenouveautype.Decefait,lerésultatseracorrect:
fquot=(float)dividende/diviseur;
Cettefois-ci,lerésultatserabienégalà1.800000.
TranstypagesLorsque vous combinez des variables de types différents, des changements de typesontappliquéssansvotreconsentement.Vousdevezenêtreconscient.
Si vous écrivez (stockez) le résultat d'une expression combinant un entier et unflottant,lerésultatseradifférentselonletypedelavariableréceptrice:
LISTING7.3Extraitdutextesourceaffectest.c
//affectest.c
unsignedcharcu=1;
floatflottant=39.99;
floatfres;
cu=flottant;
//cuvaut39
Ici, nous stockons un flottant dans un entier. Le résultat est 39 et non 39,99. C'estlogique,puisqueleschiffresaprèslavirgule(pardon,lepointdécimal)sontperdusenroute.
cu=1;
cu=cu+flottant;
//cuvaut40
Enadditionnantunevaleurentièreetuneflottante,onobtient40,etnon40.99,pourlesmêmesraisonsqueprécédemment.
cu=1;
fres=cu+flottant;
//fresvaut40.999902
Si on prend la peine de stocker le résultat dans un flottant (fres), on obtient lavaleur40,999902,beaucoupplussatisfaisante.
Vouspouvezdanscertainesconditionsforcer le typeenmentionnantunnomdetypeentreparenthèsesjusteavantlenomdelavariableouavantlavaleurconcernée.Enrepartantdesmêmesvariablesetvaleursinitialesqueci-dessus:
cu=1;
fres=cu+(int)flottant;
Cettefois-ci, lerésultatstockédansfressera40,000000etnon40,999902parcequeseulelapartieentière(39)deflottantaétépriseencompte.
Pourrésumer:
» Unecopiedefloatversintentraîneunetroncature.
» Unecopiededoubleversfloatentraîneunarrondi.
» Unecopiedelonglongversintfaitperdretouslesbitsdela
partieexcédentaire.Lerésultatn'aplusaucunsens.
» Forcerletypen'ad'intérêtquesilavaleurdedépartestdansles
limitesdutyped'arrivée.
GMP(MultiplePrecisionArithmetic):Lorsquevousaurezàréaliserdescalculssurdegrandesvaleurs sansaucunepertedeprécision, il suffirad'ajouterà lapanoplied'outilslalibrairienomméeGMPdisponibleàl'adressehttps://gmplib.org/.
Ellepermetparexempledesmultiplicationsjustesentredeuxnombresde15chiffres.
GRANDEPROMOTIONSURLESENTIERS!
Lorsque leprocesseur travailleavecdesdonnéessurquatreoctets,modifier
une valeur codée sur un ou deux octets lui coûte autant d'efforts que sur
quatre.Dufaitquelesprocesseursactuelsdesordinateurspolyvalents(nosPC
et Mac) sont dotés au minimum d'un tel processeur, une optimisation est
appliquéed'officeparlecompilateur.
Les valeurs des types char et short sont promues (converties avec
remplissagepardeszérosàgauche)versletypedebaseintpourlescalculs.
Le résultat est reconverti vers la largeur de départ pour le stockage. C'est à
vousdevousassurerqu'ilnedébordepas.
TournuresdeconfortDans le domaine des opérateurs, il existe certaines tournures qui ne sont pas desnouvellespossibilités,maisdesfaçonsd'écrirequifontgagnerdutemps.
DéclarationetinitialisationcombinéesLa première astuce permet d'économiser une instruction lorsque vous déclarez etpréparezunevariable.Sivousconnaissezsavaleur initiale,vouspouvez l'indiquerdansladéclaration.Aulieud'écrire:
charmaVar;
maVar=12;
vouscombinezlesdeux:
charmaVar=12;
Très simple et très pratique. La seule contrainte est que la valeur que vous voulezdonnerdèsledépart(valeurd'initialisation)doitpouvoirêtreconnueavantexécutionduprogramme.Vousnepouvezdoncpasciteruneautrevariable.
DéclarationsenrafaleUneautretournuresertàdéclarerplusieursvariablesdumêmetyped'unmêmegeste.Aulieud'écrire:
floatiTauxRemise;
floatiTVA2;
floatiPrixHT;
vouscombinezlestroisenséparantlesnomsparunevirgule:
floatiTauxRemise,iTVA2,iPrixHT;
IncrémentationetdécrémentationPour faire appliquer un traitement identique à toute une série d'éléments, il faut engénéraldéfinirunevariablequiva servirdecompteurdunombrede répétitionsdutraitement.
Imaginez que vous deviez avancer de dix pas pour trouver un trésor.Vous avancezd'unpas,vouscomptez«un»,vousavancezd'unautrepasetvousdites«deux».Vousgardezundécompteenmémoirepourfairedixpas,pasneuf,nionze.
Eninformatique,cegenredecompteurestréaliséavecunevariable.Vousluidonnezlavaleur0puisvousaugmentezde1jusqu'àlavaleurbutée:intmonCompteur=0;
Action_TraitementsurElementdésignéparvaleurdu
compteur
monCompteur=monCompteur+1;
Action_TraitementsurElementdésignéparvaleurdu
compteur
monCompteur=monCompteur+1;
Action_TraitementsurElementdésignéparvaleurdu
compteur
monCompteur=monCompteur+1;
etc.
Cettemanièred'écrireestunesorted'auto-référence:lirelavaleurd'unevariable,yajouter1etécrirelanouvellevaleurdanslamêmevariable.Maisc'estunpeulong.
Quandvous avezbesoind'augmenter oudediminuerunevaleur deune seuleunité,vouspouvezutilisercesdeuxopérateurs:
++ opérateurd'incrémentation
-- opérateurdedécrémentation
Vouspouvezainsiremplacerl'instruction:
monCompteur=monCompteur+1;
parcelle-ci:
monCompteur++;
Lemêmeprincipes'appliquepourdécrémenteravec--.
monCompteur--;
Avantouaprès?Lesinstructionsprécédentesontutilisélesopérateursdansleurversionsuffixe,maisvouspouvezaussiplacer l'opérateuravant (sansespace).Ladifférenceest touteennuance, mais il faut la connaître, car cela peut parfois tout changer. Voyons unexemple:
LISTING7.4Extraitdutextesourceincravap.c
//incravap.c
charcsa;
charcsb;
csa=1;
csb=5;
csa=csb++;
Après la dernière opération, la variable csa contient la valeur 5, parce quel'opérateur++ étant placé après (en suffixe ou postfixe), la valeur de la variablesourcecsbn'augmentede1qu'aprèssalecturepourcopiedanscsa.
csa=1;
csb=5;
csa=++csb;
Enplaçant l'opérateur ++ en préfixe, la valeur decsb est augmentée avant d'êtrecopiéedanscsa.
Auto-référencesabrégées(+=,-=,*=,/=)On a souvent besoin de modifier la valeur d'une variable en la combinant par unopérateur avec une valeur littérale ou la valeur d'une autre variable.Cela oblige àrépéterlenomdelavariableréceptriceducôtédroitdel'expression,commececi:
maVariableDontLeNomEstLong=maVariableDontLeNomEstLong
+5;
Une tournure permet d'éviter cette répétition du nom. Dans l'exemple suivant, lavariablecsavaut1audépart.
charcsa=1;
csa+=9;
Ellevautmaintenant10.Poursuivons:
csa*=2;
Ellevaut20.Poursuivons:
csa/=5;
Ellevautmaintenant4.Encoreuneétape:
csa-=3;
Lavariablearetrouvésavaleurinitiale,1.
Toutesces tournuressontdesastucesd'écriture.Nepas lesconnaîtrenediminueenrien ce que vous pouvez faire avec le langage, mais elles font gagner du tempsd'écritureetallègentlalectureducodesource.
Pourlesvariablesboudeuses:constVoiciuncasparticulierdevariable:lavariabledontlavaleurnepeutpasvarier.Ilsuffit d'écrire une déclaration normale de variable en ajoutant en préfixe le motréservéconst.Paradoxal,maisbienutile:
constintCOUREURS=10;
Unefoiscettedéclarationfaite,lavariableCOUREURSpossèdelavaleurnumériquelittérale10ettoutetentativedelamodifierserarefuséeàlacompilation.
L'analyseurvasurveillerlafaçondontvousutilisezlaconstantedanslasuiteducodesource.Sivoustentezdechangersavaleur,vousobtenezuneerreur:
error:assignmentofread-onlyvariable'nom'
Autrementdit,voustentezd'affecterunevaleuràunevariableenlectureseule.Cenepeutêtrequ'unebourde.
Quelestl'intérêtdedéfinirunevariablefigée?Celapermetdecentraliserunevaleurlittérale en la stockant dans un emplacementmémoire lié à un nompour citer cettevaleur,doncunevariable.Enpratique,onvaparexempleutiliserdesconstantespourdestauxdeTVAquivarientassezlentement.Encitantlenomdela«variable»,ilsuffit ensuite de modifier la valeur dans sa ligne de déclaration pour propager lanouvellevaleurpartoutoùla«variable»estcitée.
Il existeuneautre techniquepour aboutirquasiment aumême résultat.Elle supposed'écrireunedirectiveentoutdébutdufichiersource.
#defineCOUREURS10
Cegenrededéfinitiondoitêtreplacéavantlesdéclarationsdesvariablesetdessous-programmes(notammentl'indispensablefonctionmain()).
Parconvention,etpourbienlesdistinguer,lesnomsdesélémentsconstantssontécritsenMAJUSCULES.
Ladifférenceaveclaconstantedéclaréeestque#defineprovoquecommedansuntraitementdetexteunerecherchedetouteslesoccurrencesdumotEPREUVESpourlesremplacerparlavaleurlittérale3,commesivousaviezsaisilavaleur3partoutàlaplacedupseudo.
Enpratique,lesdeuxtechniquessontquasiéquivalentes.
Lebooléenexiste,ouiounon?Il nous reste un type de valeur particulier à découvrir. Dans quasiment tous lesinfolangagesd'aujourd'hui,ilexisteuntypedédiéàlalogiquepure.Ilnepermetquedeuxvaleurs:soit0,soit1.Autrementdit,OuietNonouVraietFaux.
Pourtant,enlangageC,pèredelaplupartdeslangages,cetypelogiquen'existepas.Iln'existepasdemotcléboolean.Poursavoirsiquelquechoseestvraioufaux,ouiounon,onutiliseenCuntypeentier.Silavaleurestégaleàzéro,celasignifieFaux.Dès qu'elle est différente de zéro, cela signifieVrai. Voici un exemple en pseudo-code:
si(VariableTest!=0)Action;
Cetteinstructiontestesilavariableestdifférentedezéro.Sic'estlecas,l'actionestréalisée.
Nous aurons besoin des valeurs logiques Oui/Non dans les instructionsconditionnellesquifontl'objetduprochainchapitre.
Retoursurlesrebouclagesetdébordements
Unebonneappréciationdes limitesdes typesdonneconfianceauprogrammeur, carcelaluiévitetouteunecatégoried'erreurs.
Revoyonspourclorecechapitrecommentsepassentleschoseslorsquenousallonsvolontairementplusloinquelavaleurmaximaleouminimaled'untypededonnée.
Les extraits d'affichage suivants montrent l'évolution des valeurs lorsque nous lesaugmentons de 1, en commençant juste avant le plafond, d'abord pou les entierspositifs(unsigned),puispourlesentiersrelatifs(signés).
Testsderebouclagesurentierspositifs(nonsignés)//(debord_intpos.c)
Testderebouclagedesentierssanssigne
+1dansunsignedchar:254
+1dansunsignedchar:255
+1dansunsignedchar:0
+1dansunsignedchar:1
+1dansunsignedchar:2
+1dansunsignedshort:65534
+1dansunsignedshort:65535
+1dansunsignedshort:0
+1dansunsignedshort:1
+1dansunsignedshort:2
+1dansunsignedint:4294967294
+1dansunsignedint:4294967295
+1dansunsignedint:0
+1dansunsignedint:1
+1dansunsignedint:2
+1dansunsignedlong:4294967294
+1dansunsignedlong:4294967295
+1dansunsignedlong:0
+1dansunsignedlong:1
+1dansunsignedlong:2
+1dansunsignedlonglong:18446744073709551614
+1dansunsignedlonglong:18446744073709551615
+1dansunsignedlonglong:0
+1dansunsignedlonglong:1
+1dansunsignedlonglong:2
Additionrebouclantededeuxuchar:200+64=8
Vousconstatezqu'au-delàdumaximumonretombeàzéro.Ladernièrelignedonneunexempled'additiondéfectueuse.
Voicilemêmetestmaisavecdesentierssignés:
Testsderebouclagesurentiersrelatifs
(signés)Testderebouclagedesentiersavecsigne
+1dans(signed)char:126
+1dans(signed)char:127
+1dans(signed)char:-128
+1dans(signed)char:-127
+1dans(signed)char:-126
+1dans(signed)short:32766
+1dans(signed)short:32767
+1dans(signed)short:-32768
+1dans(signed)short:-32767
+1dans(signed)short:-32766
+1dans(signed)int:2147483646
+1dans(signed)int:2147483647
+1dans(signed)int:-2147483648
+1dans(signed)int:-2147483647
+1dans(signed)int:-2147483646
+1dans(signed)long:2147483646
+1dans(signed)long:2147483647
+1dans(signed)long:-2147483648
+1dans(signed)long:-2147483647
+1dans(signed)long:-2147483646
+1dans(signed)longlong:9223372036854775806
+1dans(signed)longlong:9223372036854775807
+1dans(signed)longlong:-9223372036854775808
+1dans(signed)longlong:-9223372036854775807
+1dans(signed)longlong:-9223372036854775806
Additionrebouclantededeuxschar:100+30=-126
Vous constatez que la valeur augmente, puis atteint le maximum pour redescendreensuiteparmilesnombresnégatifs.
Vous utiliserez de préférence les variantes signées des types entiers.Normalement,saufmentioncontrairelestypesentierssonttoujourssignés.Vouspouvezvérifieravecun petit test tel que le précédent (voir les exemples debord_intpos.c etdebord_intsig.c).
Enfin, si vous prévoyez d'utiliser une variable en dividende d'une division, vousadopterezuntyperationnelàpointdécimalfloatoudouble.
RécapitulatifVoicilespointsquidevraientvousêtredevenusmoinsmystérieux:
» LesvaleursnumériqueslittéralesVNL.
» Lestypesdedonnéesetleurscorrespondancesaveclescapacité
destockagedesordinateursenoctets.
» Lesdéclarationsdevariablespoursymboliserlescellulesde
stockagedesvaleursenmémoire.
» Unepremièreinstruction,celled'affectation,pourréaliserun
travaildecopied'unevaleurnumériqueversunemplacement
identifiéenmémoire.Elleutilisel'opérateur=.
» Unepremièrecatégoried'expressions,lesexpressions
arithmétiquesquisefondentsurcinqopérateurs(+-*/%)pour
générerdesvaleursàpartird'autresvaleurs,littéralesou
symboliséespardesnomsdevariables.Leprocessusdegénération
senommel'évaluationdel'expression.
» Lestournuresdeconfortpourallégerlasaisieducode(++,+=,
etc.).
» Lesproblèmesdedébordementetderebouclagedevaleurs
lorsquel'espacerécepteuresttroppetitoudenaturedifférente.
FonctionnementlinéairePour l'instant, toutes les lignes de code source que vous pouvez écrire sontconsidéréesparl'analyseurcommeunesuitelinéairedelignes.Illesanalysedefaçonrigidedelapremièreàladernière.C'estunfonctionnementlinéaire.
Dansleprochainchapitre,nousallonsbriserleronronnementlinéaireduprogrammeen créant des situations conditionnelles pour le rendre capable de faire varier sonfonctionnementenréagissantàunchangementdesesconditionsdetravail.
A
Chapitre8Tests,fourchesetredites
DANSCECHAPITRE
» J'exécutesijeveux:ifetswitch
» Etjemerépète:whileetfor
u départ, comme dans les automates tels que les métiers Jacquard et leslimonaires, une fois que le « programme » est lancé, il se poursuit étape aprèsétapejusqu'àladernièreets'arrête,contentdelui.
Cemodedefonctionnementlinéaireestsanssurprise.Riennepeutlefairedévierdesonuniqueobjectif:arriveràexécuterladernièreinstructionetretournerdormir.
Certainespersonnessontplutôtfonceuses;ellesenchaînentlesactionsenperdantleminimumdetempsàréfléchir.D'autresagissentpuismarquentunepausepourévaluerlasituationetdéciderentredeuxsuitespossibles.C'estcequipermetdes'adapteràunenvironnementchangeant.
Cette capacité d'interrompre l'action a pu être intégrée dans le silicium. C'est unconcept majeur des ordinateurs actuels. Les actions normales de la machine quiconsistent à déplacer et àmodifier des valeurs peuvent laisser place à unmomentexceptionneloùlamachinesembledire:«Voyons,moncréateurm'aditd'arrêterdecompterunefoisarrivéà10.J'ensuisàcombien?»
Ceconceptcapital est le test. Il consisteàvérifieruneconditionetàdéciderentredeuxsuitespossiblesselonquecetteconditionsoitvraieoupas:
"Sijegagneauloto,jemerachèteunvélo."
(Sous-entendu"Sinon,jecontinueavecl'ancien.")
"Silajauged'essences'allume,jepasseàla
station."
(Sous-entendu"Sinon,jenem'yarrêtepas.")
On bascule dumode verbal impératif (Additionne ! , Copie d'ici à là ! ) aumodeconditionnel(Silavaleurdépasse9,alorslaramenerà1).
En quelque sorte, le programme s'arrête d'agir pour réfléchir. Ce n'est plusdirectement vous qui décidez de la prochaine étape, mais lui, selon la valeur quepossèdeàcemoment-làunevariableouuneexpression.
Logigrammes(organigrammes)Dèsquel'exécutionn'estplusunlongfleuvetranquille,l'analyseetladécompositiondu problème en étapes de traitement profitent d'une représentation sous formed'organigrammedeprogrammationappelélogigramme(flowchart).
Un logigramme sert à visualiser le flux d'exécution du programme. En voici unexemple:
FIGURE8.1:Logigrammeavecunecondition.
Lelosangecorrespondautest.Vousremarquezquelorsquelaconditionestsatisfaite,une action supplémentaire est effectuée alors que dans le cas contraire, le flux lacontourne. Autrement dit, la branche du NON va à droite. Cette convention peutsemblerillogique(cequiestuncomble).
Eneffet,lebonsensnousdictequec'estSIuneconditionspécialeestrencontrée,onfaitundétourparuneactionspécialepuisonreprendlefluxverticalprincipal.
Ici, c'est l'inverse.Mais ilyaunevraie raison :dans labrancheduNON,onpeutprévoir un autre test (un test imbriqué ou unSINON). Il faut donc qu'il y ait de laplacepourledessiner.
Sij'avaisunmarteau:exécutionconditionnelle
L'instruction conditionnelle existe dans quasiment tous les infolangages. Elle portepresquetoujourslemêmenomd'arbre:if(Taxusbaccata,unarbredevenurare).Enréalité,ifsignifiesienanglais.
Etymologie:L'anglais«if»vientduvieuxnorroisscandinave«doute,hésitation».Àrapprocherdedubitatifquilaisseretrouverlelatinduohabe,«avoiràchoisirentredeuxvoies».
Comment ?Mon ordinateur va douter ?Non, rassurez-vous, les ordinateurs actuelssont encore loin de pouvoir douter commeun humain. Ils vont d'abord devenir desanimauxcybernétiquespournousaiderauquotidien(etquiserontleursdresseurs?).Ilyaunedifférenceentredouteretchoisir.
Unephrasefrançaiseauconditionnels'écritcommececi:
SIconditionALORSaction_spéciale.
SIlemétroestfermé,ALORSj'yvaisàpieds.
CommenttesterenCLelangageCn'apasprévudemotALORS(maisd'autreslangagesobligentàajouterthenentrelaconditionetl'action).
VotreprogrammeCvadoncpouvoircontenircegenred'instruction:
if(expression_condition)action;
» ifestlemotmagique,lemotréservé.Apprenez-leparcœur.
» expression_conditionestuneexpressionacceptablepourle
langageC.Nousenavonsdéjàvuquelques-unesdanslechapitre
précédent.L'essentielestlerésultatdel'évaluationdecette
expression.
» L'expressionestconsidéréecommevraiesisonrésultatestvrai.En
théoriebinaire,estfauxcequivautzéro,maisn'estvraiquecequi
vautun.EnlangageC,larègleestmoinsstricte:estvraitoutcequi
n'estpaségalàzéro.
» L'actionestuneinstructionuniqueouun{blocd'instructions}.Pour
regrouperdesinstructionsdansunbloc,ilsuffitdelemarquerpar
uneaccoladeouvranteaudébutetuneaccoladefermanteàlafin.
Alors,c'estvraiouc'estfaux?Passonsenmoderalenti:
» Laconditiondutestdoitêtreuneexpression.
» Uneexpressionestquelquechosequipeutêtreévalué.
» Lerésultatdel'évaluationestnumériqueetprendlaplacede
l'expression.
Alorstentonsceci:
LISTING8.1Inspirédel'exempleif_expression.c
if(5+2)ActionConditionnelle;
Notreexpressionestuneadditiondontlerésultatest7.C'estdoncdifférentdezéro.L'actionassociéeseraexécutée.
Etsil'onneveutpasqu'ellelesoit?Nousutilisonsunopérateurspécialettrèsutilequiestincarnéparunpointd'exclamation.
L'opérateurinverseur!L'inverseur!s'appliqueauseulélémentauquelilsertdepréfixe.
Quel est le résultat si l'on applique cet opérateur à l'expression prise dans sonensemble ? Il faut dans ce cas rajouter une paire de parenthèses pour délimiter lanouvelle«non-expression».Lesespacesaméliorentlalisibilité:
if(!(5+2))ActionConditionnelle;
Avecl'inverseurlogique,toutcequiestdifférentdezérodevientnulunefoisinversé.Voicilerésultat:
//Valeurde!(5+2)=0
//Expression!(5+2)FAUSSE.
Sinousforçonsàzérounseulopérande(lavaleur5):
if((!5+2))ActionConditionnelle;
L'expressionrestevraie,car2estdifférentde0:
//Valeurde(!5+2)=2
//Expression!5+2VRAIE.
Est-ce que l'expression suivante est vraie ou fausse, compte tenu du fait que lavariablexvaut-2audépart?
((!x-2)-(x-!2))
Voicil'extraitdecodesource:
charx=-2;
//ActionAffichagedelavaleurde((!x-2)-(x-!2))
if((!x-2)-(x-!2))ActionSiVrai;
elseActionSiFaux;
Etvoicilerésultat:
//Valeurde((!x-2)-(x-!2))=0
//Expression((!x-2)-(x-!2))FAUSSE.
Ilsuffitdedécomposer:
» (!x-2)devient0-2donc-2;
» (x-!2)devient-2-0donc-2;
» Enfin,-2-(-2)donne-2+2donc0.
Avecdes valeurs littérales, ces exemples pourraient sembler sans grand intérêt.Enréalité, lorsquevousutilisereznonpasdesVNLoudesvariablessimples,maisdesappels de fonctions (chapitre suivant), ces évaluation en cascade devront être bienmaîtrisées.
(Cestestssetrouventdansl'exempleif_expression.c.)
elsepourtoutcontrôlerLorsque la condition n'est pas satisfaite, le bloc conditionnel est purement etsimplementignoréetlefluxreprendaprèsl'accoladefermante.
Vousêtesdevantvotretiroiràchaussettes.Desnoirespourletravailetdesblanchespourlesloisirs.Vousenprenezune.Onpeutsupposerquevousenvouliezdeuxdelamêmecouleur.Schématisonslalogique:
Ouvrir_tiroir;
ChercherChaussette;
Si(ChaussetteNoire)ChercherChaussetteNoire2;
Chercher_ChaussetteBlanche2;
JugerDuRésultat;
Qu'est-cequinevapas?
» Silapremièrechaussetteestblanche,nousn'ironsjamaischercher
lasecondechaussettenoire,puisquenousn'avonspaslapremière.
Toutvabien.
» Silapremièrechaussetteestnoire,letestréussitetnousallons
chercherlaseconde,puisnousreprenonslecoursdeschoses…et
cherchonsinutilementlasecondechaussetteblanchesansmême
avoirlapremière.
Lasolutionconsisteàprévoirdeuxblocsconditionnels,unpourlecasOuietunautrepourlecasNon.Seulundesdeuxseraexécuté.L'ouverturedecettesecondebranche
conditionnelle se fonde sur lemotcléelsesuivid'une instructionuniqueoud'unbloc.
if(expression_condition){
ActionSiVrai;}
else{ActionSiFaux;}
Vous remarquez que dans la nouvelle extension duelse, nous ne répétons pas lacondition.Voiciunexempleconcret:
LISTING8.2Extraitdel'exempleif_chaussettes.c
charchNoire;
//Indiquerici0ou1
chNoire=0;
if(chNoire)
//J'aiunechaussettenoire.J'enprendsuneautre.
else
//Lapremiereétaitblanche.Jeprendsuneautre
blanche.
Pour tester les deux cas possibles, il suffit de donner à la variablechNoire lavaleurinitiale1.
Rappelonsquenousnemontronspasencore lesvéritablesactionsd'affichageparcequenousn'avonspasencoredécouvertlesfonctions,etcelled'affichage,printf(),estassezcomplexe.
Pourl'instant,nousavonstestéunevaleuruniquequipouvaitêtresoitnulle,soitnonnulle. Pour écrire des tests plus intéressants, nous disposons d'une familled'opérateurspourcomparerdeuxvaleurs(ouplus).
Lesopérateursrelationnels(opérels)Les opérateurs relationnels se distinguent des opérateurs d'action déjà découverts(additionner,soustraire,etc.)pardeuxaspectstrèsimportants:
» Ilsserventàétablirunerelationentredeuxtermesquisontappelés
membregaucheetmembredroit,l'opérateurrelationnelseplaçant
entrelesdeux(nousdironspourabréger«opérel»danslasuite).
» Ilsn'ontaucuneffetsurlesdonnées;ilsserventàproduireun
résultat«àconsommersurplace».
Voicileprototyped'uneexpressionrelationnelle:
(membre_gaucheOPERELmembre_droit)
Lesdeuxmembresdoiventserésoudreenunevaleurnumérique.Cesontdoncsoitdesvaleurs littérales(VNL),soitdesexpressions.Autrementdit,engénéral, ilya troisexpressionsdanscegenredeconstruction:
» lesdeuxexpressionsàconfronter;
» lasur-expressionquirésultedelamiseenrelationdesdeux
expressions.
Cetemboîtagepeutêtrerépété.L'évaluationdelasur-expressionproduitbiensûrunrésultatnumérique.EnC,cequinousintéresse,c'estdesavoirsicerésultatestégalàzérooupas.
Voicilesopérels(opérateursrelationnels)dulangageC:
Tableau8.1:OpérateursrelationnelsdulangageC(opérels).
Opérel Nom Conditionvérifiéesi?
== égale lesdeuxmembresontexactementlamêmevaleur
!= différentde lesdeuxmembresn'ontpaslamêmevaleur
> supérieurà lavaleurdumembregaucheeststrictementsupérieure
àcelledumembredroit
< inférieurà inverseduprécédent
>= supérieurou
égalà
lavaleurdumembregaucheestsupérieureoubien
égaleàcelledumembredroit
<= inférieurou
égalà
inverseduprécédent
Onaurait pu économiser deuxopérateursd'inégalité en inversant les opérandes.Eneffet, l'expression (x>y) est absolument équivalenteà (y<x).Demême, (x>=y)équivautà(y<=x).
RédigeonsuneexpressionconditionnelleenlangageC:
LISTING8.3Inspirédel'exempleif_exprela.c
1intvarA=1;
2intvarB=2;
3inttemoin=12;
4if(varA<varB)
5ACTIONEVENTUELLE;
6
7temoin=(varA<varB);
8SUITEDESACTIONS;
Dans cet exemple, nous créons deux variables et leur donnons une valeur initialedifférente.Nouscréonsaussiunevariabledecontrôletemoin(sansaccent!)surlaquellenousreviendrons.
Remarquez à nouveau les parenthèses autour de l'expression relationnelle. Nonseulement, c'est obligatoire, mais plus lisible. Voyons d'abord le résultat del'exécutiondecebloc:
...
Expression(varA<varB)reconnuevraie!
temoinvaut1
...
Le test a réussi ! (Un rien m'émeut.) Effectivement, monsieur le processeur, lenombre1estpluspetit,etmêmestrictementpluspetitquesoncollèguelenombre2.
Mais que signifie la seconde ligne avec la variabletemoin ? En ligne 3, nousavonsbiencréélavariableenluidonnantlavaleur12.Enligne7,nousluidonnons
unenouvellevaleurquiestcellequirésultedel'évaluationdelaconditionconstituéeautour de l'opérateur relationnel <. Tout simplement. C'est bien la preuve quel'expressionestévaluéeet«remplacée»parlerésultatnumérique(0ou1).
Problème : lorsque la condition est vérifiée, nous ne pouvons faire qu'une seuleaction.Commentfaireuntirgroupé?
{Jeformeunbloc}Nous l'avons rapidement évoqué plus haut : le concept de bloc sert à regrouperplusieursactionsgrâceàuncouplededélimiteursréservésàcetusage.EnlangageC,cesontdesaccolades.
Vous pouvez enmettre où vous voulez. Si nous reprenons l'extrait de code sourceprécédent,nouspourrionsécrire:
{
intvarA=1;
intvarB=2;
inttemoin=12;
}
if(varA<varB){ACTIONEVENTUELLE1;}
Nousavonsajoutédeuxpairesd'accolades.Lapremièrepairen'aaucuneffetsur leprogramme, saufuneffet visuel.Celuiqui lit leprogrammecomprendque les troisdéclarations de variables forment un tout. Vous ne ferez jamais ce genre deregroupementpuisqu'ilnesertàrien,maisici,celapermetdevoirquecelaformeunbloc,aveclestroislignesdecontenulégèrementdécaléesversladroite(indentées).
Lasecondepaired'accoladesestmoinsvisiblemaisbienplusintéressantepuisqu'ellepermet d'implanter un groupe d'instructions autonome à la place d'une instructionunique.Dans ce cas, des conventionsdeprésentation sont à adopterpourmaintenirunebonnelisibilité:
if(varA<varB){
ACTIONEVENTUELLE1;
ACTIONEVENTUELLE2;
ACTIONEVENTUELLE3;
ACTIONEVENTUELLE4;
ACTIONEVENTUELLE5;
}
Certainsindententdequatreespacesparniveau.Ici,nousnouslimitonsàdeux.Notezbienlapositiondesdeuxaccolades.L'ouvranteestsurlalignedutest.
L'accoladefermanteestàpartsursaligneenalignementaveclemotcléif.Onvoitimmédiatementl'étenduedubloc.
Lesaccoladessortenttoujourspardeux.
UnebourdefréquenteIlnedoityavoiraucunpoint-virguleisoléàlafindelalignedumotclé!
Lorsquele testsuivantréussit, ilnesepasseriendeplus.ActionSiOKestexécutéedans tous les cas, puisque l'instruction se trouve après la fin du bloc conditionnelmarquéparlesignepoint-virgule:
if(reponse==OK);ActionSiOK;
ActionNormaleSuivante;
Cettecatastrophedelogiquedifficileàcorrigerdécouledelasimpleprésenceinutiledusignepoint-virgulejusteaprèsl'expression.LeCacceptececicommeinstruction:
;
Elleestvide,maisellepossèdesonsignedeponctuation,doncl'analyseurestcontent.
Voyonscommentcombinerplusieursconditions.
ExpressionscomplexesNoussommesdansunparcd'attraction.Supposonsunpanneauà l'entréed'ungrandhuitquidiraitceci:
Tuas12ansouplus.
Tumesuresaumoins1,20m.
Siturépondsàcesdeuxconditions,tupeuxmonterdanslegrandHooplaboom.
Sinon,mangedelasoupeetreviensplustard!
Lapremièresolutionpourautomatisercefiltraged'entréeconsisteàimbriquerunsecondblocconditionneldanslepremier.
SiSil'impératif:conditionsimbriquéesSi la condition est satisfaite, rien ne vous interdit d'implanter un autre blocconditionnel,«enchâssé»danslepremierpourimposerunesecondecondition.Notezbienlapositionetlenombred'accoladesdebloc:
LISTING8.4Extraitdel'exempleif_ifhoopla.c
intage;
floattaille;
intageYves=10;
intageAnnie=14;
floattailleYves=1.30;
floattailleAnnie=1.35;
//Yvesveutentrer
age=ageYves;
taille=tailleYves;
if(age>11){//B1a
if(taille>=1.20){//B2a
//ActionValiderBillet;
}//B2a
else{//B2b
//ActionInterdireCarTropPetit;
}//B2b
}//B1a
else{//B1b
//ActionInterdireCarTropJeune_Taille_inconnue;
}//B1b
//Annieveutentrer
age=ageAnnie;
taille=tailleAnnie;
if(age>11){//B1
if(taille>=1.20){//B2a
//ActionValiderBillet;
}//B2a
else{//B2b
//ActionInterdire(troppetit);
}//B2b
}//B1
Lorsquevous imbriquezdesblocsconditionnels, ilestessentieldebienrepérer lescouplesd'accolades.
Pourlasecondecandidate,nousavonséconomiséleelsedeniveau1puisqu'ilestinutile(l'autreaussid'ailleurs).Dèsqu'uneconditionestfausse,iln'yapasvalidationdubillet.
Pourenvisagerdesconditionsdetestplussophistiquées,nousdisposonsd'uneautreespèced'opérateursquipermettentderelierdeuxàdeuxdesexpressionsbaséessurdesopérels.
Lesopérateurslogiques(opélogs)Unopérateur logique permet de relier deux expressions de test pour construire unesur-expression.
Lesopélogs&&et||Pourtesterdeuxconditionssimultanément,ilsuffitdecombinerlesdeuxexpressionsavecunopérateurlogique(opélog).Iln'yenaquedeuxainsiquelenégateur:
Tableau8.2:OpérateurslogiquesdulangageC(opélogs).
Opélog Nom Résultat
&&
ET
logique
(condi1)&&
(condi2)
Vraiseulementsilesdeuxconditionssont
vraies.
|| OU
logique
(condi1)||
(condi2)
Fauxseulementsilesdeuxconditions
sontfausses.
! NON FaussiVraietVraisiFaux
Voyonscommentreformulerletestd'accèsaumanègeavecchacundesdeuxopélogs.
LISTING8.5Extraitdel'exempleif_hooplaboom.c
intage=13;
floattaille=1.10;
//Ici,actionsdelecturedesvaleurs
if((age>11)&&(taille>=1.20))
//Tupeuxfaireuntour!
else
//Uneautrefois.
//IdemmaisavecleOU
if((age<12)||(taille<1.20))
//Uneautrefois.
else
//Tupeuxfaireuntour!
Le fichier exemple téléchargeable (if_hooplaboom.c) contient des appels à unefonctiondelecturededonnéesauclavierscanf()quipermetdetestertouslescas.Ici,ilsuffitd'imaginerdeuxvaleurspourl'âgeetlataille.
Quatrecassontpossibles:
» tropjeuneettroppetit;
» tropjeuneetassezgrand;
» assezâgémaistroppetit;
» assezâgéETassezgrand(seuleconfigurationquinousintéresse).
Penchons-noussurlepremiertestbasésurleETlogique,l'opélog&&:
if((age>11)&&(taille>=1.20))
Laconditiond'accèsestrempliesil'âgeeststrictementsupérieurà11ETsilatailleest au moins égale à1.20. Il suffit qu'une des deux sous-expressions soit fausse(égale à zéro) pour que l'action associée soit ignorée. C'est bien ainsi que nousraisonnonsauquotidien.
La touche du ET commercial & est assez facile à trouver en haut à gauche. Enrevanche,leOUlogiquesymbolisépardeuxbarresverticales||estuncaractèrequelesnon-programmeursutilisentrarement.Voicioùletrouversurleclavier:
» SurPC,c'estlatouchedutiret-etdu6maisenmaintenantla
toucheAltGr.
» SurMac,c'estencombinantlestroistouchesMajAltL.
Voyonsdoncmaintenantl'utilisationduOUlogique:
if((age<12)||(taille<1.20))
L'expression globale est vraie dès qu'une des sous-expressions l'est. Il suffit doncd'inverser la logique par rapport au ET. Il suffit que l'âge OU que la taille neconviennepaspourrefuserl'entrée.
Sivousutilisezl'inverseur!,pensezauxparenthèses.Enguised'exercice,cherchezdansquelcascetteexpressionseravraie,celafaitautantdebienauxneuronesqu'unsudoku:
if(!(age>11)||!(taille>=1.20))
Ilsuffitqu'unedesdeuxsous-expressionssoitvraiepourquelevisiteursoitreconduitàlasortie.
Lapremièreestvraiesilevisiteurn'aPASplusdeonzeans.
Lasecondeestvraiesisataillen'estPASsupérieureouégaleà1,20m.
Vousnepouvezpasabrégerl'exécutiond'unblocconditionnelsaufàinstallerunlabelaupoint de chute et à y sauter avecungoto, ce que la plupart des programmeurs
abhorrent.Lechapitresuivantabordecessautsimpératifs.
Nioui,ninon?Lorsqu'il s'agit de tester plusieurs valeurs d'une même variable, vous pouvezaccumulerlestestsifsimplesjusqu'àtrouverlabonnevaleur:
LISTING8.6Extraitdel'exempleif_else_ventilo.c
intcommande=0;
//Saisiedelavitesseentre1et4
if(commande==1)printf("Vitesse1choisie\n");
if(commande==2)printf("Vitesse2choisie\n");
if(commande==3)printf("Vitesse3choisie\n");
if(commande==4)printf("Vitesse4choisie\n");
Mais cela devient assez malcommode, surtout s'il y a un bloc conditionnel avecaccoladesaulieud'uneinstructionuniquecommeici.
La solution existe : c'est l'instructionswitch, un véritable poste d'aiguillage. Enguise de récréation avant de découvrir cet autre mot clé fondamental, allons voircommentlesgrainsdesablesedébrouillentpourexécuteruntestconditionnel.
DanslasalledesmachinesNouspartonsd'untrèscourtexemplecomplet.Nouslaissonscettefois-cilesélémentsencoreinconnus,maisenitaliques.
Ne vous intéressez qu'aux lignes en gras. Celle avecprintf()est un appel à lafonctiond'affichagedetoutcequiestplacéentrelesguillemets.
LISTING8.7Exempleif_jumpasm.c
//if_jumpasm.c
#include<stdio.h>
intmain()
{
intvarA=7;
charmonchar='d';//Soit0x64
printf("#####EDITIONSFIRST####\n");
if(varA==7){
monchar='A';//Soit0x41
}
elsemonchar=66;//Soit0x42
return0;
}
Nousdéclaronsunevariablepourl'expressiondetestetuneautredanslaquellenousstockons la valeur numérique de la lettredminuscule (100 en décimal, soit 64 enhexadécimal).
Nous affichonsunmessage (#####EDITIONSFIRST####) suivi d'un saut deligne(\n)etnousentronsdansleblocdetest.Letestréussitpuisquenousavonsécritlavaleur7dansvarAenladéclarant.Donc,nousécrasonslecontenudemoncharenystockantlavaleur65endécimal(41enhexadécimal).Ladernièreinstructionfaitquitterleprogramme.
Voici l'aspect général d'un outil d'étude du fonctionnement du programme (ledébogueurOllyDbg).
FIGURE8.2:Vuegénéraled'unesessiond'étudeducodemachine.
Voici l'affichage de la portion correspondante du programme en cours d'exécutiondansledébogueur.
La colonnedegauche indique les adressesmémoire.Prenez comme repère la ligneavecletextedumessage(nousl'avonsinsérépouraiderànousyretrouver).
Remontezdedeuxlignesetlisezuneligneaprèsl'autredanslatroisièmecolonne:
» Àl'adresse004013E7,noustrouvonsuneactiondecopieMOV
DWORD…(déplacerquatreoctets)danslavariablevarA(lenoma
disparu)delavaleur7(lechiffre7terminel'instruction).C'est
cohérentpuisquenousavonsdéclarélavariabledetypeint,donc
icisurquatreoctets.
» Lalignesuivantefaitdemêmeenstockantdansl'autrevariable
moinsspacieuse(MOVBYTE…)lavaleurnumériquedelalettred
minuscule(64enhexadécimal).Nousavionschoisiunetaillechar,
surunoctet(BYTE).
» Nousretombonsensuitesurlacopiedumessage.C'estunMOV
DWORDparcequenousstockonsl'adressemémoiredupremier
caractèredumessageetlesadressesdanscetexempleoccupent
quatreoctets(32bits).Nousverronslespointeursdansunautre
chapitre.
» L'instructionsuivanteen004013FBappelle(CALL)unsous-
programmequiparchanceestvisibledanslehautdelafigure,
jusqu'en004013D8.LeRETNfaitretourneràlalignequisuitl'appel,
doncen00401400.C'estlapartiequinousintéresse.
CMPDWORD(àignorer….),7
» Nouscomparons(CMP)lecontenud'uneadressemémoireavecla
valeurlittérale7.C'estbienlatraductiondenotreinstructiondetest
if(varA==7).Cettecomparaisonmodifiedesindicateurs
internesduprocesseur(lesflags).L'instructionsuivanteestlaplusimportantedetoutes.Elleexploitelerésultatdelacomparaisonen
sautant(JumpifNotZero)oupasversuneadressepeuéloignée
(short)oùsetrouvelaprochaineinstruction.
JNZSHORTif_jumpa.0040140E
» Silacomparaisonn'apasarmél'indicateurdezéro(sil'évaluation
del'expressionn'apasétéfausse),noussautonsàl'adresse
indiquéepoureffectuerl'actionsuivante:
MOVBYTEPTR(àignorer….),42
FIGURE8.3:Zoomsurlecodemachinedutestif.
C'estbiennotresecondeinstructiond'affectation(monchar=66;)puisquelavaleur 42 en hexadécimal correspond à 66 en décimal ! Les instructions suivantesprovoquentlafinduprogramme(RETN).
Maissil'expressionestfausse(lavariablen'estpaségaleà7),lesautn'estpasfaitetonpoursuitavecl'instructionquisuitleJNZ.C'estuneautreinstructiond'affectation.
MOVBYTEPTR(àignorer….),41
C'est notre première instruction d'affectation (monchar='A'; ) puisque lavaleur41enhexadécimalcorrespondà65endécimalquidésigneleAmajuscule.
Pour éviter d'exécuter les instructions de l'autre branche conditionnelle, il ne resteplusqu'àsautersanscondition(JMP)au-dessuspourrejoindrelesinstructionsdefindeprogrammeen00401413:
JMPSHORTif_jumpa.00401413
Etc'esttout.
Vousvenezdedécortiquer le fonctionnementd'unprogrammeauniveauélémentairedes impulsions électriques dans la matière ! Dans un livre d'initiation, c'estremarquable.Quelques essais rapidesmontrent que tout cet ensemble d'instructionspeutêtreexécutéenvirondeuxcentmillionsdefoisenuneseconde.
Lepostedebranchement:switchL'instructionconditionnelleswitchestpratiquemaissondomained'emploiestpluslimité.Ellen'estpasaussifondamentalequeleifuniversel.
Le mot switch signifie commutateur. Son origine est la notion de bâton pourmodifierunmécanisme.
Dès que vous devez scruter une variable pour la confronter tour à tour à plusieursvaleursobligatoirementconnuesàl'avanceetdetypeentier(deuxcontraintes),vouspouvez adopter switch à la place d'un enchevêtrement de if.. else ifelsepeudigeste.
Citonsquelquesdomainesd'applicationsdeswitch:
» lechoixd'uneoptiondansunmenu;
» lasélectiond'unplatdansunrestaurant;
» lasélectiond'unmodedefonctionnementd'unappareil.
Les cas attendus doivent tous être connus à l'avance, car toutes les valeurs nonconsidérées finissent dans un récipient communmarqué par le mot clédefault.Voicicequel'onappellelasyntaxeformelledeswitch:
switch(expression_condition){
caseVNL1:Action;
break;
caseVNL2:
caseVNL3:Action;
break;
default:Action;
}
Observezbienlesarticulations:
switch(){
case:;
case:;
case:;
case:;
}
Iln'yapasdepoint-virguleaprèsl'accoladefermante.L'instructionpossèdeuncorpsdélimitéparsonjeud'accolades.Danscecorps,ilyadescas,maislachargeutile(laséried'actions)dechaquecasn'estpasdélimitéepardesaccolades.C'est inutileetrisquedevousinduiredansl'erreur.Pourquoi?
La lectured'unestructureswitchest linéaire,de lapremièreà ladernière ligne.Lorsqu'uncasestdétecté,touslestestsdecassuivants(dansl'ordredelecture)sontcommeignorésmaistoutesleursinstructions,jusqu'àl'accoladefermanteduswitch,sontexécutées,mêmecellesdescasquinesontpassatisfaits!
Il n'y a qu'une exception : la branche du cas poubelle marquée par le mot clédefault.Ellen'estexécutéequesiaucuncasnel'est.
C'estvicieux,maisparfoistrèspratique.Pourévitercetenchaînementpargravité,lasolutionestdelerompreaveclemotclébreak.
Dufaitquevousaurezbienmoinssouventbesoind'enchaînerplusieurscasquedelesdistinguer,voiciunerègled'or:
Terminezchaquecaseparuneinstructiondesortiebreak;.
Passons à un exemple. Vous vous souvenez du projet de commande de ventilateurquelquespagesplushaut?Nousallonslereformuleravecunswitch.
LISTING8.8Extraitdel'exempleswitch_ventilo.c
intcommande=0;//Changercettevaleurpourtester
switch(commande)
{
case1://ActionVitesse1;
break;
case2://ActionVitesse2;
break;
case3://ActionVitesse3;
break;
case4://ActionVitesse4;
break;
case0://ActionStop;
default://ActionCommandeInconnue;
}
IlyaundefaultSansbranchedefault,siaucuncasneconvient,latotalitédublocdeswitchestignorée,commes'iln'existaitpas.Laprochaineactionestcequisetrouvejusteaprèsl'accolade fermante du bloc. Mais il est souvent utile d'intercepter cet imprévu.Justement,toutestprévuenCgrâceaumotclédefault.
Conservons l'exemple de la commande d'un ventilateur. Si l'utilisateur indique unevitesse non prévue, par exemple 5 (peut-être a-t-il vraiment très chaud), rien ne sepasse. La branchedefaultpermet par exemple de l'informer qu'il a choisi unevitesseinexistante.
Dansl'exemple,ilyauneinstructionbreakpourclorechaquecas,saufceluidelavaleurzéro.Elleestinutilepourlederniercasavantdefault,cardefaultn'estvisitéquesiaucunautrenel'est.Ilestdoncignorédanslescinqcas.
CequeswitchsaitlirePour l'expressionà tester,vouspouvezformuleruneexpressionaussicomplexequedésiré, mais le résultat final de l'évaluation doit être entier. Vous pouvez doncindiquerunnomdevariable(sinontoutcelaneserviraitàrien),maisl'évaluationdecetteexpressiondoitaboutiràunevaleurentière,puisquecesontdesvaleursentièresquivontluiêtreconfrontéestouràtour.
Sivoustentez:
floatnivocuve=12.30;
switch(nivocuve){
...
vousrecevezuncourrierderappel:
error:switchquantitynotaninteger
pardon,maislavaleuràcomparerparswitchn'estpas
entière
Votrecasem'intéresseChaque cas de test doit être une valeur constante, connue au moment de l'analysependantlacompilation.Sivoustentezd'indiquerunnomdevariable,vousobtenezcemessagedecompilation:
error:caselabeldoesnotreducetoaninteger
constant
erreur:lavaleurdecasen'estpasunentier
invariable
#definepourunmondeplusagréablePourrendreplusdigestesetplusparlantslesdifférentscas,vouspouvezprofiterdelatechniquededéfinitiondevaleurslittéralesparpseudos.Cesontcesdirectivesqu'ilfautajoutertoutaudébutdutextesource:
#defineMAGRETCANARD1
#definePOULOPOT2
#defineSTEAKPOIVRE3
Notezqu'iln'yaPASdepoint-virguleàlafind'unedéfinitiondeconstante.
Une fois ces pseudo définis, nous pouvons, plus bas dans le texte, écrire un blocswitchainsi:
switch(commande)
{
caseMAGRETCANARD://Servir1;
break;
casePOULOPOT://Servir2;
break;
caseSTEAKPOIVRE://Servir3;
break;
default://ActionSiPasDansMenu;
Sivousomettezlesinstructionsbreak;,ilseproduitceci:
» touslesclientsquiontcommandéunmagretmangenttroisplats;
» tousceuxquiontcommandéunepouleaupotmangentaussiun
steakaupoivre.
UnetransitionsansconditionAprèscettevisitedesdeuxstructuresconditionnellesifetswitch,voyonsl'autretechnique fondamentale qui permet de rompre le flux normal de l'exécution de lapremièreàladernièreligne:lesrépétitionsouboucles.
Répétitiond'instructions:séquenceitérative
On le dit assez : un ordinateur, cela répète bêtement sans jamais se lasser. Pasd'accord!
1. Toutd'abord,leprocesseurnesaitpasqu'ilrépètelamême
action(desoutilslogicielspermettentdemesurerletemps
passédanslesboucles,maisleprocesseurn'aqu'uneidéefixe:
exécuterlaprochaineinstructionqu'onluidonne).
2. Répéteruneactionestunestratégieintelligentelorsquecette
répétitionamènepasàpasàunbut,commelorsquevous
rentrezchezvousàpied:
TANTQUE(PasMaison)
{
AvancerPiedDroit;
AvancerPiedGauche;
}
EnfilerCharentaises;
EnlangageC,etdansdenombreuxdescendantsduC,vousdisposezdedeuxmanièresdecréerunebouclederépétition:
» labouclewhilequirépètetantquesonexpressionconditionnelle
estvraie;
» laboucleforquiluiressemblemaisenregroupantdeux
opérationsavecsonexpressionconditionnelle.
Nousverronsaussilavariantedewhilequis'écritdo...while.Ellenes'endistinguequedufaitqu'elleagitavantderéfléchir.
Tantqu'ilyauradel'amour:whileLa construction while est la reine des boucles. Tant que son expression derebouclageentreparenthèsesestvraie,ellereboucle,etreboucle,etreboucle.
Elle exécutedansce cas soituneunique instruction (accolades facultativesdanscecas),soittoutleblocdélimitéparlesaccolades.
Lasyntaxeformelledewhileestminimale:
while(expression_condition){
ActionSiVrai;}
}
Neconservonsquelesarticulations:
while(){
;
}
Lenon;duwhileIci non plus, pas de point-virgule après l'accolade fermante ! Et comme pour lesautresconstructions,s'iln'yaqu'une instructionàrépéter,onpeutomettre lecoupled'accolades.
Dufaitquenousavonsdéjàbeaucouppratiquélesexpressionsconditionnelles,l'étudedesbouclesserarapide.
Stopouencore?Lepointessentieldesbouclesestquel'expressionassociéedoitêtrevraie.C'estunecondition d'entrée et de maintien dans la boucle, c'est-à-dire de poursuite de larépétition.Maisd'abord,unpeudesport.
AubordduprécipiceVousvoulezressentirlefrissondel'infinisanspérir?Voyezceci:
while(1){
break;
}
Ouf!Nousl'avonséchappébelle.Laconditionseravraietantqueunseradifférentdezéro,cequinouslaissedutemps.Maisc'estcequel'onappelleuneboucleinfernaledontonnesortqu'enarrachantlapriseélectrique.
Heureusement, le programmeur s'est juste fait peur, puisqu'il a prévu unmoyen des'éloignerduvideparuncoupdebreakdèslepremiertour.
Laconditiondoitdoncêtrevraieaumoinslapremièrefois,carsinon,onpasseàlasuite.Maiselledoitdevenirfausseunefoisentrédanslaboucle,auboutd'uncertainnombredetours,mêmesicenombredetoursestincertain.
LafindeladernièrephraseprouvequelefrançaisesttoutdemêmeplusnuancéqueleC.
Unnombredetoursvariable,maisn'est-cepasledomained'excellencedenotrepetitanimalnommévariable?
Unefoisentrédanslaboucle,etmisàpartlasortieàlahussardeparbreak,laseulesortiepropreconsisteàrendrefaussel'expressiondeboucle.
Laconditiondeboucledoitbasculerdevraiàfauxdanslaboucle.
Iln'yaquewhilequivailleUnefuséepartparfoisaprèsl'heure,maisjamaisavant.Elledoitattendrelesignaldudépartettoutlemondes'yprépareaumoyend'uncompte-à-rebours.Nousavonsbienuneactionquipermetd'arriveràlamiseàfeu,puisquenousutilisonslatournurededécrémentation:
LISTING8.9Extraitdel'exemplewhile_kontarbour.c
intkontarbour=400;
while(kontarbour!=0)
{
//AfficherLeDécompte;
kontarbour--;
}
//Lancement;
kontarbour--;
quidiminuedeunlavaleurdelavariableàchaquepassage.
Pouruncasd'applicationplusfouillé,repartonsdel'exempledesplatsaurestaurantquenousavionsgéréavecunswitch. Insérons toute la structurede choixdeplatdansunebouclewhilequi testeunevariablepoursavoirsi leserviceest finioupas.Audébutduprogramme,nousforçonslavariableà0,puisqu'endébutdeservicelaconditiondefindeserviceestfausse.
Nous testons commeconditiondeboucle le fait que cen'estPAS la finde service.Dans l'exemple, nous redemandons à chaque fin de tour si c'est l'heure de fermer.Danslapratique,lechangementdevaleurpourraêtreréaliséparunefonctionexternequirenvoielavaleur(nousverronslesfonctionsauprochainchapitre).
LISTING8.10Extraitdel'exemplewhile_switch_magret.c
intcommande=0;
intfinService=0;
while(!finService){
switch(commande){
caseMAGRETCANARD://Servir1;
break;
casePOULOPOT://Servir2;
break;
caseSTEAKPOIVRE://Servir3;
break;
default://ActionSiPasDansMenu;
}//Findublocswitch
//Saisie1pourMagret,2pourPoule,3pourSteak
//DemanderSiFermeture1siOui,0siNon
}//Findublocwhile
Laconditiondeboucleinverselavaleurlogiquedelavariable:sipasfindeservice,servirladernièrecommande.
Dans lepremier tour,nouscherchonsquoi servir alorsquenousne sommesencorejamaisalléprendre lacommande.Lavariableétant initialiséeàzéro,nous tombonssur default puis prenons la commande. Pour les plats (tours) suivants, on prend lacommandepuisonvérifiequecen'estpasladernière.
La logique réelle n'est pas parfaitementmodélisée, car si on vérifie que le servicen'estpasfiniavantdeprendrelaprochainecommande,onvalaprendresanspouvoirlaservir,puisqu'auprochainretourentêtedeboucle,l'expressionserafausse.
Lasolutionconsisteàajouteruntestaprèslademandesifermeturepoursortirdelaboucleparbreak,doncavantdeprendreunecommandedetrop.Ilresteencoreuninconvénient : la question de la fermeture est inutilement posée avant la premièreprisedecommande.
Cegenrederaisonnementvousdonneuneidéedelarecherched'unalgorithmepourmodéliserunprocessusmétier,uneactivitéimportantedel'analyste/programmeur.
Voyonsmaintenantlapetitesoeurdewhilequiprendleschosesàl'envers.
L'avoirfaitaumoinsunefois:do…whileCertaines activités peuvent être décrites ainsi : « Parfois, il faut s'y reprendreplusieursfois,maisengénéral,c'estbondupremiercoup.»
La boucle do…while exécute son bloc conditionnel une première fois AVANTd'effectuerunepremièrefoissontestpoursavoirs'ilfautrépéter.
Sil'expressionestfausseetlerestedanslepremiertour,iln'yauraeuqu'untour,cequirevientàécrirelesinstructionsdefaçonpurementlinéaireendehorsdetoutblocconditionnel,etlabouclen'auraserviàrien.Envoiciuneillustration:
LISTING8.11Extraitdel'exempledo_unefois.c
inttoujoursFaux=0;
do{
//ActionFaiteAuMoinsUneFois;
}
while(toujoursFaux);
Laconditionabeauêtretoujoursfausse,leblocdudoestexécutéunefois.
L'extraitsuivantproduituneboucleinfiniedontnoussortonsparbreak.Ajoutez lecouplede//decommentairesendébutde la lignebreaksivousvoulezrendrel'exécutionéternelle(vousensortezparCtrlC):
inttoujoursVrai=1;
do{
//Action;
break;
}
while(toujoursVrai);
Voyonslasyntaxeformelledelavariantedo..while:
do{
ActionSiVrai;}
}
while(expression_condition);
Neconservonsquelesarticulations:
do{
;
}
while();
Le;dudoCettesyntaxeestpiégeuse,puisqu'il fautajouterunpoint-virgule toutà la fin,aprèsl'expressionconditionnelleduwhile.C'estunesourced'erreurparcequ'iln'yapasun tel signe dans le while normal, sauf lorsque vous ne lui attribuez qu'une
instruction unique sans accolades, mais dans ce cas, le point-virgule est celui del'instruction.Laraisond'êtredecetteanomalieestpeuclaire.
Vous pouvez essayer de glisser une instruction avant ce signe bizarre. Elle serarefusée.Ilfautdoncs'ensouvenir.
do..whilesetermineparunpoint-virgule.
Voyons un exemple dumonde réel, celui d'un basketteur qui s'entraîne à réussir aumoinsunpanier.
LISTING8.12Extraitdel'exempledo_basket.c
intpanier=0;
charessais=3;
do{
panier=LancerBallon();//Fonctionquirenvoie0
ou1
essais--;
if(essais==0)
panier=1;
}
while(!panier);//Attentionau;
//AfficherBravo;
Nousdémarronsàtroisessais,etréduisonslenombreaprèschaquelancerdeballon,cequipermetdesortirdelaboucle.
LancerBallon()seraune fonction appelée à cet endroit et renvoyant soit 0 siraté,soit1sipanier.Lesfonctionssontaumenuduprochainchapitre.
Voyonspourclorecechapitrelaturbo-bouclefor.
Jesaisforbiencompter:forLa boucle for est dans la pratique spécialisée lorsqu'il s'agit d'appliquer untraitementuncertainnombredefoisensebasantsuruncompteurquiestincrémenté
oudécrémenté.
Cetteconstructionembarquetoutcedontelleabesoindanssoncoupledeparenthèsesquijouentlerôledelotdeparamétrage.Voicid'abordlasyntaxeformelledefor:
for(init;condition;action){
ActionSiVrai;}
}
Uniquementaveclesarticulations:
for(;;){
;
}
Leblocdeparamétrageméritedes'yarrêter.
(init;condition;action)
Les troismembressont facultatifs,mais lesdeuxpoints-virgulenon.Notezunpiègepossible ici : contrairement à la logique, il n'y a pas de point-virgule après letroisièmemembre,action.
forn'aquedeuxpoints-virgulesdanssesparenthèses.
Pour illustrer la capacité de for à embarquer tout le nécessaire pour faire sontravail, étudions les quatre boucles for suivantes. Les explications sont situéesaprèschaqueextrait.
LISTING8.13Extraitdel'exemplefor_test.c
intcpt=0;
//Version1:toutestvide,boucleinfinie!
for(;;){
//Action;
cpt++;
if(cpt==10)break;//Poursortir!
}
Version1.Nousdéclaronsd'abordnotrevariabledetravailcpt(uncompteur).Sinous laissonsvides lesparamètresdefor,nousobtenonsuneboucle infinie.Nousdevonsdoncajouteruntestpourensortir.
//Version2:conditioninsérée,ifinutile
cpt=0;
for(;cpt<10;){
//Action;
cpt++;
}
Version 2. Si nous insérons la condition de rebouclage à sa place attendue (endeuxième), l'animal est dressé. Nous sortons au bout de dix tours. Nous pouvonsenlever l'issue de secours. Cependant, nous devons encore ramener le compteurà0avantd'entrerdanslaboucle(puisqueletestprécédentl'alaisséà10).
1//Version3:initetconditioninsérées
for(cpt=0;cpt<10;){
//Action;
cpt++;
}
Version3.Nousinjectonsaussil'instructiondepréparationetn'avonsplusbesoindepréparerlecompteuravantlaboucle.
//Version4:init,conditionetincrémentation
for(cpt=0;cpt<10;cpt++){//Action;}
Version 4. Et voici la version complète de la bouclefor. Nous avons injecté entroisièmemembreuneinstructionpourfairevarierlecompteurafindepouvoirsortirde laboucle.C'est iciquebiendesprogrammeurs se trompent, et cen'estpas sansraison.
Lenon;duforLetroisièmemembreestuneinstruction(cpt++ici),maisexceptionnellement,ilnefautpasdepoint-virguledefind'instructionàcetendroitprécis.
Pasdepoint-virguleautroisièmemembredefor
Puisqu'ilne resteplusqu'une instructiondans lecorpsdeboucle,nousenprofitonspour la remonter en fin de première ligne. Vous pouvez juger de la compacité durésultat:touttientsuruneligne.
Leforaimel'effortPour illustrer l'utilisation classique de la boucle for, demandons de calculerquelquespuissancesdedeux.
Lelotdeparamètresdeforautoriseplusieursinstructionspourchaquemembre.Ilsuffitdelesséparerpardesvirgules(unedesraresutilisationsdecesymbole).NousdéfinissonsunebutéehauteMAXpuisdéclaronsunevariabledegrandecontenance(sur8octets)etunepluspetitepourmémoriserlapuissancededeux.
LISTING8.14Extraitdel'exemplefor_deux.c
#defineMAX32768*32768
intmain()
{
longlongvalor;
intp;
for(valor=2,p=1;valor<=MAX;valor*=2,p++)
{
//AfficherValeurDe_p;
//AfficherValeurDe_valor;
}
return0;
}
Puisarrivelaboucle.Ellecomportedeuxinitialisations,uneexpressiondeboucleetdeuxinstructionsdetraitementexécutéesàchaquetour.
Notezbienlesvirgulesetpoints-virgules.
for(valor=2,p=1;valor<=MAX;valor*=2,p++){
Les instructions du premier membre ne sont exécutées qu'avant le premier tour deboucle (vous vous en doutiez),mais celles du troisièmemembre ne sont exécutéesqu'enfindeboucle,pasaudébut!
Lemembredetraitementduforestexécutéenfindeboucle.
LeforidéalLa possibilité d'injecter des instructions « normales » dans les paramètres deforpermetparfoisdefairedisparaîtreentièrementsonblocconditionnel.
Voiciunexemplequisimuleunrendez-vousentre lesdeuxnombres0et100. Ilsserejoignentàmi-chemindansuneconvergenceamoureuse.
LISTING8.15Extraitdel'exemplefor_conver.c
inta,b;
for(a=0,b=100;a!=b;a++,b--);
//aetbsesontrejointesà50!
Admirezlacompacité:
for(a=0,b=100;a!=b;a++,b--);
Doubleinitialisation,conditiondebouclageetdoubletraitement.Toutletravaildontnous voulons confier le contrôle à for est dans le troisième membre de sesparenthèses.Rienàajouter(saufbiensûrunaffichagedesvaleursouuneutilisationselonlesbesoins).
AveccertainscompilateursC,vouspouvezmêmeoublierlepoint-virguleuniquequisuitlaparenthèsefermantedesparamètresdeboucle.
Compareretsauter,voilàtout!Les mots clés des blocs conditionnels et répétitifs sont tous des parents proches.Commel'amontrénotrepetiteplongéedanslecodemachine,toutcelasetermineencomparaisons(CMP)suiviesdesautsimpératifs(JMP)oupas(JNZetautres).
Enguisederévision,voyezcommeonpeutobtenirleseffetsd'unetechniqueàpartird'uneautre.
Exercice1:Créezuneboucleforavecunebouclewhile.
Exercice2:Créezuntestifavecunebouclewhile.
Exercice3:Créezuntestifavecunebouclefor.
Cherchezunpeuavantderegarderlessolutions.
Réponseàl'exercice1.Uneboucleforavecunebouclewhile:
inti=0;
while(i<10){ACTION;i++;}
estéquivalentà:
for(i=0;i<10;i++;){ACTION;}
Réponseàl'exercice2.Untestifavecunebouclewhile:
inti=0;
while(i==0){ACTION;i=1;}//UNSEULTOUR
Réponseàl'exercice3.Untestifavecunebouclefor:
inti=0;
for(;i==0;){ACTION;i=1;}//UNSEULTOUR
Onprésentegénéralementlesblocsconditionnelsetlesbouclesderépétitioncommedeux concepts distincts. En réalité, il s'agit de variantes dumême grand principe :celui de branchement, c'est-à-dire de saut à une autre instruction que celle situéenaturellementaprèscelleencours.
Etensuite?Unénormeconceptnousattenddansleprochainchapitre:celuidesous-programme.Ilcentuplelapuissancedetousceuxdécouvertsjusqu'ici.
V
Chapitre9Enfonctiondevous()
DANSCECHAPITRE:
» Leblocd'instructionsprivatisé
» Leroietsesvassaux
» Lesquatremodes
» Variableslocalesetglobales
» if(fonk())fonk();(récursion)
aleurs, variables, expressions, opérateurs, boucles et conditions suffisent àconcevoirquelquestraitementsutiles.Maisilarriveunmomentoùvousavezécritunesériedelignesquieffectuentuntraitementquevousavezbesoinderéutiliser.
Nous avons appris que le couple d'accolades { } servait à regrouper plusieursactions.Celanousaétéutiledanslesinstructionsdetestetdebouclepourpouvoirfaireplusd'uneactionlorsquelaconditionétaitvraie.Commentfairepourrendreceblocde lignes indépendantdu resteafindepouvoirendemander l'exécutiondepuisn'importequelleautreligneduprogramme?
Une première solution consiste à utiliser le mécanisme qui anime les boucles derépétition:lesaut.
Auloup!Auloup!gotoEtsil'onpouvaitdonnerunnomàunblocpourenmarquerledébut?Celas'appelleuneétiquetteouunlabel(remarquezlesignedeux-points).
ActionX;
NomDeMonBloc:
{
Action1;
Action2;
Action3;
}
Supposonsquequelques lignesplus loindans la suiteduprogramme,onait besoind'exécuterànouveaulestroisactionsdenotreblocnommé.C'esttrèsfacile:ilsuffitdedemanderdefaireunsautverslapremièredesactionsdubloc.
En langageC, lemot clé approprié s'écritgoto (aller vers, sauter).Vous le faitessuivredunomdubloc(sanslesignedeux-points,maisavecunpoint-virgule,puisquec'estuneinstruction).
Les programmeurs chevronnés qui se sont perdus dans ce livre d'initiation vonts'exclamer:«Bouhlevilainauteur!Ilparledumauditmotgoto.»Tenezbon,nousallonsvoirpourquoiilnefautpasignorergoto,mêmes'ilfautchercheràl'éviter.
Dans un saut, vous détournez le flux normal en installant un branchement vers uneautreinstructionquecellequisuitcelleencours.Vousneconservezaucunetracedecequevousfaisiezavantdevousdétourner.Après lesaut,vousêtesperdudansunlabyrinthe.Commentreprendrelasuitedesopérationsnormales?
Imaginezquevousalliezmangerchezdesamis.Aumomentderepartir,vousconstatezquevous avez totalementoubliéoùvoushabitiez.Paspratique.Vousavezperdu lecontexte.C'estcequel'onreprocheàgoto.
Ilfaudraitinstallerdesmarque-pagespartout(deslabels).L'expérienceamontréquele programme devenait très difficile à relire et à faire évoluer une fois qu'il étaitcriblédesautsdanstouslessens.Regardezlavuedynamiquedutextesourcesuivant.
Lavraieetformidableréponseàcebesoinestlesous-programme,plusprécisémentlafonction.
FIGURE9.1:LeCSpaghettiFestival.
LeconceptdefonctionPour créer ce concept, il a suffi de combiner trois techniques déjà vues dans leschapitresprécédents
» leregroupementdeplusieursinstructionsdansunblocdélimité
pardesaccolades;
» l'attributiond'unnomcommepourunevariable,saufquecenom
vadésignerledébutdubloc;
» unmécanismedesautversceblocnommé,maisrevisitépour
conserverquelquepartl'adressededépartavantdesauterafinde
pouvoiryrevenir.
FIGURE9.2:Schémad'uneséquenced'appels.
Dansunsautsimple,vousperdezlefil,surtoutaprèsplusieurssautsimbriqués.Dansun appel, vousgardezun fil d'Arianedans le labyrinthe.L'appel de fonction est unaller/retour.
En programmation moderne, l'appel de fonction est la seule technique utiliséeexplicitementpoursuspendrelefluxd'exécutionnormal(uneligneaprèsl'autredans
lesensdelecture).
Unevariantede l'appel est le rappel (callback) qui consiste à faire confiance à uninconnu : vous transmettez l'adresse de début d'une de vos fonctions à un autreprogrammequidécideradumeilleurmomentpourdéclencherl'appelplustard.
LesuzerainetsesvassauxLa notion d'appel de fonction instaure l'équivalent d'une monarchie primitiveconstituéed'unroisuzerainetdesesvassaux.Unefonctionincarneleroi,rienn'existeavantelle.Elletientsespouvoirsdelavolontéducréateurduprogramme(enfaitdel'utilisateur quand il fait démarrer le programmeou l'application).C'est la fonctionprincipalemain().
Touteslesautresfonctionssontappeléesdirectementparcesuzerainouindirectementparunvassalderangsupérieur.
L'ensembleconstitueun schémaordonnéd'ordresetdecomptes-rendus (lesvaleursrenvoyées) qui permet assez facilement de comprendre comment fonctionne leprogramme,aussibienparlecturedutextesourcequeparobservationdel'exécutionavecunoutilcapablededétecterlesappelssuccessifs.
Lanotiondefonctionoffredecefaitdesavantagestrèsappréciables:
» modularisationdestraitementspardécoupageenopérations
élémentaires;
» simplificationdelamaintenance;
» meilleurequalitéducodeparmaintiend'unebonnevisibilitédes
fluxdevaleurs;
» réutilisationfaciledefonctionsdansd'autresprojets.
Etlalisten'estpasexhaustive!
Sousleprogramme,lafonctionDans le texte source, une fonction n'est pas une construction complexe. Voici sasyntaxeformelle:
typeretnomfonction(paramètres){
//Déclarationslocales;
//Instructionslocales;
return(valeur);
}
Enneconservantquelesarticulations:
(){
}
C'estunblocclassique,commeceuxdesbouclesetconditions.L'accoladeouvrantedoitêtreprécédéed'aumoinsdeuxéléments:
» unmotclépourspécifierletypedelafonction(vouschoisissez
parmilesnomsdetypesdevariablesdéjàconnus);
» unidentificateurservantdenomsuiviobligatoirementd'unepaire
deparenthèses,videoupas,maisaucunpoint-virgule;
» lecoupled'accoladesdubloc,quevousconnaissezbien
maintenant.
Uneconventionpratiquelorsquel'onciteunnomdefonctiondansuntexteconsisteàfaire suivre le nom de la fonction d'une paire de parenthèses vides, même si lafonctionpossèdeenréalitédesparamètresd'entrée(doncdesparenthèsesnonvides).
Cen'estpastoujourscequevousvoyezLe fait d'ajouter la définition d'une fonction dans un texte source ne suffit pas à enprovoquerl'exécution.Vouspouvezdéfinirdesdizainesdefonctionsavantlafonctionprincipale main(). Si vous ne les appelez pas, elles sont totalement ignorées,commesic'étaientdescommentaires.(Voyezaussil'exemplef_invisibles.c.)
Intéressons-nous d'abord à l'unique fonction qui se tapit dans l'ombre depuis troischapitres.Elleabienméritécethonneur:lafonctionprincipalemain().
Lesuzerain:lafonctionmain()Tous les exemples des trois premiers chapitres de cette partie ont été des extraits,parceque lanotionde fonctionn'étaitpasabordée.Nousavionsmontréà la findupremierchapitrequepourfairefonctionnercesexemples,ilfallaitlesinsérerdansunréceptacle,etceréceptacleestunefonction.
EnC,uneinstructionesttoujoursdansleblocd'unefonction.
En C et dans tous les langages impératifs, il existe obligatoirement au moins unefonctiondanstoutprogramme.C'estlafonctionprincipalenomméemain().C'estlapremièreetladernièreàêtreexécutée.
intmain(void){
//Déclarationsdevariables;
//Instructionsinéluctables;
//Instructionsconditionnelles;
//Instructionsrépétées;
//Appeldefonction;
//etc.
//Motcléreturn(valeur);
}
La structure générale de main() est la même que celle de toutes les autresfonctions,maissescaractéristiquessontparticulières.
EntréeenmatièreLa ligne de tête de fonction débute sa définition. En conformité avec la syntaxeformellemontréeplushaut,ellecomportequatreéléments:
» int:Vousindiqueziciletypedelavaleurquelafonctionrenvoie
enfind'exécution.Lafonctionprincipaleétantlapremièreà
s'exécuter,ellen'apasétéappeléeparuneautrefonction,maispar
lemécanismedechargementdeprogrammedusystème
(Windows,MacOS,Linux).Lavaleurqu'ellevarenvoyerestdecefait
engénéraluncodepourinformerquetouts'estbienpassé
(valeur0)oupas(autrevaleur).
» main:Lafonctionmain()estlaseuledontlenomestimposéen
C.
» ():Lesparamètresd'entrée.Lafonctionmain()estspécialeau
niveaudesparamètres.Vousêtesautoriséàladéfinirsoitsans
aucunparamètre(void),soitavecdeuxparamètres,maisleurtype
etleurnomsontimposés.Nousyreviendrons.
» {}:Leblocdelafonction,quel'ondésignesouventparcorps,
puisquec'estcettesériedelignessourcequiestlaraisond'êtrede
lafonction.Ondoitfinirparrencontrerl'accoladefermante}pour
délimiterlafinducorpsquicoïncidedanslecasdemain()avecla
find'exécutionduprogramme.
ElleaducorpsDans le corps de main(), nous trouvons au minimum un appel de fonction, etsouventplusieurs.Danslesciblesdesappels,onpourraentrouverd'autres,etainsidesuiteencascade.
Lorsquevousn'utilisezpasd'appelsdefonctions,vouslaisseztoutesvosdéclarationset instructions dans la fonction main(), ce qui donne une exécution linéaire.L'écoulement du temps pendant l'exécution reflète la progression ligne après lignedans le texte source. Les seules exceptions sont locales : ce sont les répétitions(whileetfor)etlesblocsconditionnels(ifetswitch).
Dèsquevousdéfinissezunepremière fonctionenplusdemain(),puisajoutezunappelàcelle-cidansmain(),vousvouséchappezdecettemonotonie.Vousquittezl'autoroutepourvisiterlesparages(etreprendrel'autorouteaumêmeéchangeur).
main()rendcompteausystèmeLa fonctionmain()se termine comme ses subordonnées par un renvoi de valeurconstituédumotreturnetd'unnomdevariableoud'uneVNL.
Cette valeur est récupérée par le système en fin d'exécution du programme. Celapermetdedétecterunefinanormaleetd'agirenconséquence.
Cettepossibilitéestsurtoututiliséeparlesprogrammesutilitairesetlestraitementsdefond qui ne dialoguent pas ou quasiment pas avec l'utilisateur, par exemple unprogramme qui démarre automatiquement toutes les heures pour faire une copie desécuritéd'undisqueversunautre.
Quandmain()déborde
Undemi-siècledepratiquedelarédactiondetextessourcesamontréqu'ildevenaitdifficile de gérer un projet dès qu'une fonction comptait plus d'environ cinquantelignes. La première et unique fonction au départ, main(), est donc la premièreconcernée.
Pourl'alléger,ilsuffitdedélimiterunblocdelignesquireprésenteunecertaineunitéfonctionnelle,dedéplacer tout leblocà l'extérieurducorpsdemain()et de luidonnerunnom.
Voyonsdoncmaintenantlecasgénérald'unefonctionautrequemain().
ChoisirlemodedesfonctionsConcevoirunefonctionsupposedeprendredesdécisions:
» Queltypedevaleurdoitêtrerenvoyé(uneseulepossible)?
» Quelnomchoisirpourbiensuggérerl'objectifdelafonction?
» Combiendeparamètresd'entréesontnécessairesetqueldoitêtre
letypedechacun?
Cesdécisionspermettentdedéfinirquatremodesdeformulationd'unefonction:
Mode1:fonctionn'attendantrienenentréeetnerenvoyantrien.
Mode2:fonctionattendantunevaleurenentréeetnerenvoyantrien.
Mode3:fonctionn'attendantrienenentréemaisrenvoyantunevaleur.
Mode4:fonctionattendantunevaleurenentréeetrenvoyantunevaleur.
Cesmodesn'ont riend'officiel.C'estuneclassificationquenousproposonsdanscelivrepouryvoirplusclair.Voiciunexempledanslequelsontdéfiniespuisappeléesquatre fonctions, une parmode. Les noms choisis pour les fonctions suggèrent leurmode.Letextesourcecompletseracommentéunpeuplusloin.
FIGURE9.3:Lesquatremodesd'unefonctionenaction.
Biennommer,c'estbienLechoixdesnomsdesfonctionsesttrèspersonnel.Certainesdevosfonctionsserontlefruitdedizainesd'heuresderéflexionetdemiseaupoint.Commevousêtesseulmaîtreàbord,vousaureznaturellementenviedecélébrervotrevictoiresurlemondeobscurdesboguesenchoisissantdesnomsquivousplaisent.
Unefonctionétantunblocd'actionsautonome,quiditaction,ditverbe.Pourquoinepasréserverlesnomspourlesvariablesetlesverbespourlesfonctions,commedanscesquelquesexemples:
floatcalculerTVA();
shorttesterExistenceFichier();
chartrouverSiAnneeBisex();
intafficherListeCli();
Lescontraintessontlesmêmesquepourlesvariables:pasdelettresaccentuées,pasdechiffreenpremièreposition,quedeslettres,deschiffresdécimauxetlesigne_.
Dans notre exemple, les noms des fonctions sont assez suggestifs, même si nousn'avonspaschoisid'utiliserdesverbes.
CegenredenomreprendunetraditionqueconnaissentceuxquiapprécientlamusiquefrançaisepourclavecinduXVIIIe(Couperin,Froberger,Forqueray,Duphly,Rameau,Royer,etc.).
Ledire,c'estlefaire:l'invocationPour utiliser une fonction, il suffit d'écrire son nom accompagné de paramètresacceptablesentypeetennombre.
Làoùvouscitezcenom,pensezautypedelafonction:c'estunevaleurdumêmetypequivaapparaîtreàlaplacedunomunefoislafonctionexécutée.
ÉtudedesquatremodesL'exemplesuivantmontrelesquatremodesd'utilisationd'unefonction.
LISTING9.1Textecompletdef_modes.c
//f_modes.c
#include<stdio.h>
//Mode1:pasdeparametres,renvoidevoid
voidLaMuette(void){
//AffichageLaMuettevousparle.
//Pasdereturnpuisquetypevoid
}
//Mode2:unparametre,renvoidevoid
voidLaParame(intparamA){
//AffichageLaParamevousparle.
if(paramA==9999)//ActionLaParame
//Pasdereturnpuisquetypevoid
}
//Mode3:pasdeparametres,renvoidevaleur
shortLaValeur(void){
//AffichageLaValeurvousparle.
return(16383);
}
//Mode4:parametresetrenvoidevaleur
shortLaMatheuse(intpA,intpB){
intiMaval;
//AffichageLaMatheusevousparle.
iMaval=pA+pB;
return((short)iMaval);
}
intmain()
{
intiValTest,vA,vB;
//AffichageTestdesquatremodesdefonction.
LaMuette();//Invocationdirecte
//iValTest=LaMuette();impossible!
LaParame(9999);
iValTest=LaValeur()-16000;
//AffichageLaValeur-16000donneiValTest
vA=88;vB=11;
iValTest=LaMatheuse(vA,vB);
//AffichageLaMatheuseatransmisiValTest
//Affichagemain()varenvoyer0.
return0;
}
Repérezd'abordchacundesquatrecorpsdefonctionsentreaccolades.Aveclalignede tête, cela constitueunedéfinitionde fonction.Pour l'analyseur,une fonctiondoitêtre connue (définie) aumoment où il en rencontre la première utilisation. Ici, lesquatrefonctionssonttoutesappeléesdepuislafonctionprincipalemain()dont lecorpsestsituéaprèselles.Nousverronsuneautrefaçondefaireunpeuplusloin.
Fonctiondemode1(LaMuette)Voicid'abordl'invocation:
LaMuette();//Invocationdirecte
Etvoicilecorpsdedéfinitiondelafonction:
voidLaMuette(void){
//Déclarationsdevariableslocales
//Actions_LaMuette;
//Pasdereturnpuisquetypevoid
}
Certainsprestatairesfonctionnentdanscemode:vousleurcommandezuntravail,ilsont toutcequ'il fautpour le faire…et le font. Ilsn'ontpasdecompte-renduàvousdonner (type de fonction void) et pas besoin de précisions de votre part pourtravailler(listedeparamètresvideoumentionvoid).
Cemodeconvientpourdes traitementsgénériquesquin'ont aucun risqued'échouer,puisquevous,entantquedemandeur,nepourrezjamaissavoirsilestravauxsesontbiendéroulés(saufàtesterunevariableaccessibledepuislafonctionappelanteetlafonctionappelée).
Maisc'estnotrepremièrerencontreaveclemotclévoid.Quesignifie-t-il?
Renvoyerrienounerienrenvoyer(void)?
Lemotclévoidsignifievide,rien, lenéant.Utilisécommetyped'unefonction, ilindique que la fonction va renvoyer le pseudo-type nommé void, qui est un casparticulier.Ce«type»permetàl'analyseurdevérifierquevousutilisezlafonctioncommeprévudanssadéfinition.
Vous ne pouvez pas citer une fonction de typevoid du côté source (droit) d'uneaffectation.L'exemplesuivantestabsurde:
maVariableReceveuse=FonctionVoid(param);
Lafonctionrenvoieunenon-valeur ;onnepeutdoncpas lacopier.Enrevanche, lemotcléconfirmequevousn'avezpasoubliédedéciderdutypederetour.
Lemotclévoidseprononce«vo-ide»,mêmeparmilesprogrammeursfrançais.
Fonctiondemode2(LaParame)En conservant l'image d'un prestataire, certains sont incapable de laisser unemalfaçon,mais ils ne peuvent réaliser leurmission que si vous leur fournissez desdétailsspécifiques:monterunmur?Maisquelleshauteuretlargeur?
Voicid'abordl'invocation:
LaParame(9999);
Etvoicilecorpsdedéfinitiondelafonction:
voidLaParame(intparamA){
//Déclarationsdevariableslocales
if(paramA==9999)//Action_LaParame;
//Pasdereturnpuisquetypevoid
}
Ici, il n'y a qu'un paramètre d'entrée. En pratique, le nombre de paramètres d'unefonctionest souvent limitéàdeux, troisouquatre.S'il faut luien fournirplus,vousprofiterez du conteneur à valeurs nommé tableau que nous découvrirons dans leprochain chapitre.Vous pouvez ainsi envoyermille valeurs numériques en citant lenomdutableau.
Vousconstatezqu'ilfautindiquerletypedevaleurduparamètrepuissonnom.Cenomestpurementlocal.Iln'estpasconnudanslafonctionappelante.
Dans notre exemple, nous appelons la fonction avec la VNL (valeur numériquelittérale) 9999, mais nous aurions pu citer un nom de variable du type adéquat,variable connue dans la fonction appelante. Lors du transfert, c'est la valeurnumériquequepossèdelavariableàcemomentquicircule.
La conséquence est évidente : si vous demandez à une fonction de multiplier unnombre:
intReceveuse;
intmonDemi=2;
Receveuse=CalculerDouble(monDemi);
la fonctionva recevoirunecopiede lavaleur (2)etcalculer lavaleur4qu'ellevarenvoyer dansReceveuse, maismonDemin'aura pas changé ! Les murs entrefonctionssontétanches!
Parvaleur?Cettetechniqueestditedetransfertoudepassagedeparamètreparvaleur.Commentfaire lorsque vous voulez faire modifier la variable que vous transmettez ? Latechnique est unpeuplus délicate à utiliser, car elle suppose d'avoir découvert lespointeurs,commenousleverronsdansledernierchapitredecettepartie.Sachezquecela consiste à envoyer l'adresse de la variable grâce à l'opérateur & placé enpréfixe.Onécriraitl'appelainsi:
CalculerDouble(&monDemi);
NomsdesparamètresLesnomsquevousattribuezauxparamètresnesontutilisablesquedanslafonction.Ilsdéfinissentdesvariableslocalesetn'ontabsolumentpasbesoindecoïncideraveclesnomsdesvariablescitésenparamètresréelsdanslesappelsàlafonction.Dansl'exempleCalculerDouble()ci-dessus, la fonctionpeut recevoir lavaleurdemonDemimêmesielledéclareleparamètreainsi:
intCalculerDouble(intValeur2Depart){//...
Fonctiondemode3(LaValeur)Voicid'abordl'invocation:
iValTest=LaValeur()-16000;
Etvoicilecorpsdedéfinitiondelafonction:
shortLaValeur(void){
//Déclarationsdevariableslocales
//Actions_LaValeur;
return(16383);
}
Renvoyer unevaleur est lemode le plus courant de définitiond'une fonction.Maisellenepeutenrenvoyerqu'uneetuneseule.
Iln'yapasdenomdevariableàassocierautype,puisquec'estjustementlenomdefonction qui en tient lieu. Toute fonction (sauf de type void) équivaut à uneexpression.Sonexécutionéquivautàl'évaluationdecetteexpression.Ilenrésulteunevaleur, valeur qui peut être copiée dans une destination, retransmise à une autrefonction,ouplussimplementutiliséeaumêmetitrequ'uneVNL:
iValTest=LaValeur()-16000;
L'appeldefonctiondonneunevaleur(sitypenonvoid)
Lanature(pasletype)delavaleurrenvoyéedépenddugenredefonction:
» Pourunefonctionmathématique,parexemplequicalculelecarré
d'unnombre,vousrenvoyezévidemmentlerésultat.Celavousévite
dedevoircréerunevariablepourystockercettevaleurpuisla
réutiliser.
» Pourunefonctionquieffectueuntraitementpouvantéchouer,le
mieuxestdefairerenvoyeruncodepoursavoirsitouts'estbien
passéoupas.Lavaleurpeutmêmedonnerunindicesurlegenre
d'erreur.Danscetteapproche,vousfaitesrenvoyerzéroquandtout
aréussietunevaleurnumériquedifférenteselonlegenred'erreur.
» Ondésignesousletermedeprédicatunefonctiondontlenomest
uneaffirmationlogique,commeFichierOK()ou
BarriereOuverte().Avecuntelnomdefonction,onpeut
supposerqu'ellerenvoiezéroseulementsilaréponseàlaquestion
estnégativequandlefichiern'estpastrouvéouquandlabarrière
n'estpasouverte.
Ces deux conventions contradictoires sont pourtant celles préconisées par lesmeilleursprogrammeursdumonde.Vouspouvezalleroutreettoujoursrenvoyerzéroquandtouts'estbienpassé,maissoyezconstantdansvoschoix.
Vousvousrendrezcompte!Toute fonction devrait se terminer par sa dernière ligne. Comment ? Mais c'estévident,pourriez-vousdire:puisquec'estunbloc,auseindubloclaloidelagraviténousfaitdescendredeligneenlignejusqu'àladernière(ignoronslessautslocauxdesifetwhile).
Mais puisque la fonction doit renvoyer une valeur, elle doit utiliser le mot cléreturnsuivid'unnomdevariable(oud'uneVNL).
Donc,returndoitêtreladernièrelignedelafonction?Pasnécessairement.Dansl'exemple de la section de début de chapitre «Le concept de fonction » , les deuxfonctionsfonc1()etfonc2()utilisaientdeuxsortiesparreturn.L'essentielestque tous lesfluxd'exécutionpossiblesaboutissentàunreturn.L'exécutionnedoitjamaispouvoirseterminersurl'accoladesansqu'unreturnaitété rencontréavant.
Quandlafonctionrenvoievoid,neperdezpasdetempsàajouterreturn(void);.L'analyseuracomprisquevousvouliezrenvoyerdurien.
Bienquereturnnesoitpasunefonction,maisunmotclé,l'habitudeveutquel'onécrivelavaleuroulavariabledontonrenvoielavaleurentreparenthèses.C'estplusjolique:
returnnomvariable;
Fonctiondemode4(LaMatheuse)Voicid'abordl'invocation:
iValTest=LaMatheuse(vA,vB);
Etvoicilecorpsdedéfinitiondelafonction:
shortLaMatheuse(intpA,intpB){
intiMaval;
//Autresdéclarationsdevariableslocales
//Actions_LaValeur;
iMaval=pA+pB;
return((short)iMaval);
}
C'estlemodeleplussocial.Lafonctionréclamesesconditionsdetravailàcellequil'appelle,cequiluipermetdes'adapteràtouteunegammedesituationsetellerendcompteparuncoded'erreuroulefruitdesontraitement.
Vous voyez que les noms des variables sont différents dans l'appel et dans laréception.
Remarquezlamentiondetranstypage(short)avant le renvoidevaleur.Elleestsanseffetnégatif.Voicipourquoi:
Lesdeux«para-variables»pAetpBsontdetypeintaussi.Leuradditionaussi.Toutvabien.
LavariableiMavaldanslaquellenousstockonslerésultatdel'additionestdetypeint.
Enrevanche,nousavonschoisiderenvoyerunevaleurde typeshort.Problème :typesdifférents!
En ajoutant un transtypage entre parenthèses, nous forçons le type de la variable àdevenirshort (deuxoctetsau lieudequatre).C'estunebonne idée,maisoubliercetteprécautionn'estpassanctionnéparl'analyseur.Pourquoi?
Pourplusieursraisons:
» Entrelestypesentierss'appliqueunmécanismedepromotion
automatiqueversletypenaturel(int)depuislestypespluspetits
(charetshort).Lorsqu'unprocesseursaitadditionnerdeux
valeurssurquatreoctets,celaluiprendplusdetempsdelefaire
avecdessous-unitésdesontypenaturel(lalargeurdemot
machine,vousvoussouvenez?).Mêmesilesdeuxparamètres
avaientétédetypeshort(enprévisiondutypeàrenvoyer),lefait
delesadditionnerlesauraitconvertisentypeint.
» Deplus,nousstockonslerésultatdansunevariableint.Au
momentdureturn,l'analyseuracceptel'incohérence.Pourlui,
c'estàvousdesurveillerquelavaleurréellequevousvoulezfaire
renvoyernedébordepasdurécipientdemandé.
Enpratique,silavaleuràrenvoyerdébordedescapacitésdutype,
l'erreurneserapassignalée,maisilyaurapertedetoutoupartie
desdonnées.
Supposons que nous appelions la fonction ainsi en sorte que le résultat débordelégèrementdescapacitésdutypedelafonction:
LaMatheuse(16384,16384);
Danslafonction,remplaçonslesvariablespardesvaleurs:
iMaval=pA+pB;
//Devient
32768=16384+16384;
return((short)iMaval);
//Devient
return((short)32768);
Observez la dernière ligne : nous demandons de forcer vers le type short. Pardéfaut, saufmention préfixeunsigned, ce type est signé. Il est donc limité à laplage +32 767 à -32 768. Stocker la valeur positive 32 768 y est impossible.Résultat?Rebouclage,commemontrédans lechapitresur les typesdedonnées.Lafonctionvarenvoyerunedonnéefausse:-32768.
Pour réglercecasd'exemple, il suffiraitdemodifier la signaturede la fonction (saligne de tête) en spécifiantintou bienunsignedshort au lieu deshortpourletypeetd'enleverletranstypagequidevientalorsinutile,incohérentetnéfaste.Celapermetderécupérerlavaleurattendue(+32768).
LAFONCTIONAUSENSMATHÉMATIQUE
Unefonctionmathématiquegénèreunevaleurf(x)enfonctiond'uneautre(x).
Pourjouercerôle,lafonctioninformatiquedoitaccepterunevaleurd'entréeet
renvoyerunevaleurdesortie.
La syntaxe de définition d'une fonction peut étonner puisque le type de la
valeurdesortieestindiquéd'abord,puislenomdelafonction,puisseulement
leoulestypesd'entrée.Ilfautsesouvenirqueletypedelafonctiondétermine
vraiment le type que possédera la valeur qui va être produite à la fin de
l'évaluationdel'expression-fonction.C'estcequipermetd'écrire:
floatprixTTC,prixHT;
prixTTC=prixHT+calculerTVA(prixHT);
Auretourdel'appelàcalculerTVA(),lenomdelafonction(soninvocation)
estremplacéàcetendroitparunevaleurnumériquedetypefloat.Lenom
s'estévaporé.
Annoncez-vous!(déclarationsetprototypes)
Pourappelerunefonction,ilfautquel'analyseurconnaisselafonctionlorsqu'ilatteintlalignequil'appelle.
Dans l'exempleprécédent, les quatre corps des fonctions appelées depuismain()ont été rédigés avant le corps de main(). Lorsque l'analyseur est tombé sur lepremier appel, il connaissait déjà (sens de lecture naturel) tous les détails de lapremièrefonction.
Enpratique,lesprogrammeursaimentorganiserlecodesourceensortequ'ilsuiveàpeu près l'ordre d'exécution. Autrement dit, la fonction principale main() estgénéralement définie en premier. Pour éviter toute plainte de l'analyseur, l'astuceconsisteàimplanterunprototypepourchaquefonction.
Le prototype ressemble beaucoup à la ligne de tête de la définition de fonction. Ilcontient le type, le nom et les types de paramètres, ce qui suffit à l'analyseur pourvérifierquevousutilisezensuitecorrectementlafonction.
RappelonslalignedetêtedeLaMatheuse():
shortLaMatheuse(intpA,intpB){
Voicileprototypecorrespondant:
shortLaMatheuse(intpA,intpB);
Notezbienquec'estunedéclaration,commepourunevariable.La lignese terminedoncparunpoint-virgule(cequin'estpaslecasdeladéfinitiond'unefonctionquiestunesorted'expression).Ensomme,l'accoladeouvrantedisparaît(iln'yapasdeblocsurleslignessuivantes)etnousajoutonsunpoint-virgule.
Laplupartdescompilateursacceptentqueleprototypenementionnequelestypesdesparamètres ( LaMatheuse(int, int) ), mais c'est une bonne habituded'indiquerlesnomségalement.
Voici ledébutdenotreprécédentexempleune fois les fonctionsdéplacéesaprès laprincipale(nousnelereproduisonspasinextenso):
LISTING9.2Débutdutextesourcedef_modproto.c
//f_modproto.c
#include<stdio.h>
voidLaMuette(void);
voidLaParame(intpA);
shortLaValeur(void);
shortLaMatheuse(intpA,intpB);
intmain()
{
intiValTest;
//Testdesquatremodesavecprototypes.\n");
LaMuette();//Premierappel
/*Suitedutextesourceavecfindemain()
puislesquatrecorpsdesfonctions.
*/
//...
Dufaitquelafonctionestunensembleautonome,elleconstitueunesortedecitadelleisolée dumonde extérieur.Elle communique avec sondemandeur (son suzerain) aumoyend'unsasd'entréeetd'unsasdesortie.
Lafonctionregroupedeséléments(valeursetactions)dansunréceptacleprotecteur.C'est une forme basique de la technique nommée encapsulation (bien que sous uneformemoinscomplètequedansleslangagesorientésobjets).
LacitadelleduvassaletlesestrangersLeroiasanscessebesoindedistribuersesordresàsesvassauxenleurscitadellesdes provinces amies. Il envoie des coursiers à ses grands vassaux pour gérer lesaffairesduroyaume.
Les grands vassaux vont si nécessaire envoyer leurs propres coursiers chez leurssubordonnésderanginférieur.
Chaquecoursierdoit revenir chez lui, et il nepeut ramenerqu'unobjet (unevaleurd'untypeconvenuàl'avance).C'estlavaleurindiquéeavecreturn.
Chaquefonctionpossèdesonpont-levisgardé.C'estparcepont-levisquedesvaleurspeuvententrerdanslafonction.Cesontlesparamètresd'entrée.
Lesvariableslocalessontcommeleslivresdecomptesduvassal.
» Del'extérieurdelafonction,vousn'avezpasaccèsauxvariables
déclaréesdanslebloc.Cesontlesvariableslocalesdelafonction.
» Del'intérieurdelafonction,vousn'avezpasaccèsauxvariables
desautresfonctions.
» Laseuleexceptioncorrespondauxvariablesglobalesdéclaréesen
dehorsdetoutefonction,audébutdutextesource.Toutesles
fonctionsdumêmetexteyontaccès.
LISTING9.3Textesourcedef_varloc.c
//f_varloc.c
#include<stdio.h>
intvarGlob=11;
intF1(){
intvarF1=345;
//intvarMain=4;//Inconnueici!
varGlob=12;
printf("//varF1deF1()=%u\n",varF1);
printf("//varGlobdepuisF1()=%u\n\n",
varGlob);
return(0);
}
intmain()
{
intvarMain=1;
intvarF1=2;
printf("//varMaindansmain()=%u\n",varMain);
printf("//varF1dansmain()=%u\n",varF1);
printf("//varGlobdansmain()=%u\n\n",varGlob);
F1();
printf("//varMaindansmain()=%u\n",varMain);
printf("//varF1dansmain()=%u\n",varF1);
printf("//varGlobdansmain()=%u\n",varGlob);
return0;
}
Observezlesmessagesproduitsparl'exécutiondecetexemple:
//varMaindansmain()=1
//varF1dansmain()=2
//varGlobdansmain()=11
//varF1deF1()=345
//varGlobdepuisF1()=12
//varMaindansmain()=1
//varF1dansmain()=2
//varGlobdansmain()=12
Queconstatet-on?
» varF1vaut2dansmain(),mais345danslafonctionF1().Ce
sontdeshomonymesquis'ignorentetn'interfèrentnullement.
» varGlobestmodifiéedansF1(),cequiestprouvéauretourdans
main().
» varMainn'estpasaccessibledansF1()etvarF1deF1()ne
l'estpasdansmain().
UneportéedevariableséphémèresUne variable déclarée (créée) dans une fonction est locale à cette fonction. Lafonctiondevientunpetitservicequisedébrouilletoutseulpourremplirsondevoir.Songuichetdesortie,c'estreturn(valeur);unpointc'esttout.
Cette rigueuroffre l'avantaged'éviter tout risquedemodification involontaired'unevariabledepuisuneautrepartieduprogramme.Mêmesivousdéclarezunevariabledemêmenomailleursquedanslafonction,leCgèredeuxvariablesdistinctes.Selonl'endroitoùsetrouvel'actionencours,ellevas'appliqueràl'uneouàl'autre.
Unevariablelocaleaunrayond'actionlimitéparlesmursdesafonctionpropriétaire,maiselleaaussiuneduréedevielimitéeparcesmêmesmurs.
Unevariablelocaledefonctionestautomatiquementdétruiteensortiede
fonction(saufexception).
C'esttoutàfaitdéconseillé,maispersonnenevavousempêcherderéutiliserunnomdevariableexistantdansuneautrefonction.
Lavariableenmodeveille:static
Parfois, on veut qu'une variable locale survive à la fin d'exécution d'une fonction,parce qu'on va rappeler la même fonction plus tard et qu'il serait intéressant derepartirdelavaleurqu'elleavaitaupassageprécédent.
C'estpossible.LeCaprévulemotcléstatic.Supposezquevousvouliezsavoircombien de fois vous avez appelé une fonction. Il suffit d'y déclarer une variablestatiquequiconserverasavaleurmêmeaprèslafind'exécutiondelafonction.Unpeucommesielleétaitstockéeauréfrigérateurjusqu'auprochainappel.
Illustrons ces aspects avec un programme complet. Comme dans les exemplesprécédents,lesactionsd'affichagedevaleurssontremplacéespardescommentairesenattendantquenousabordionslesfonctionsprédéfiniesdeslibrairies,etnotammentprintf().
LISTING9.4Textesourcedef_static.c
//f_static.c
#include<stdio.h>
intmaFonc(intparam);
intmain()
{
intmaVar=5;
//***Projetf_static.c***
//MaVardemain()vautxxavantappel
maFonc(maVar);
//MaVardemain()vauttoujoursxxapresappel!
maVar=maFonc(maVar);
//MaVardemain()vautenfinyyapresappel
maFonc(maVar);
//MaVardemain()vauttoujoursyyapresappel!
return0;
}
intmaFonc(intparam)
{
staticshortk2Passages=0;
intmaVar;
intmaVarLocale=0;
maVar=param;
k2Passages++;
maVarLocale++;
maVar++;
//k2Passages=aa
//maVarLocale=bb
//MaVardemaFonc()=cc
return(maVar);
}
Voici les messages qui montrent l'évolution des valeurs de ce petit troupeau devariables:
***Projetf_static.c***
//MaVardemain()vaut5avantappel
//k2Passages=1
//maVarLocale=1
//MaVardemaFonc()=6
//MaVardemain()vauttoujours5apresappel!
//k2Passages=2
//maVarLocale=1
//MaVardemaFonc()=6
//MaVardemain()vautenfin6apresappel
//k2Passages=3
//maVarLocale=1
//MaVardemaFonc()=7
//MaVardemain()vauttoujours6apresappel!
Parcourez le texte source et les résultats en observant surtout la variablek2Passages. Elle a été déclarée static et conserve sa dernière valeur d'unappelausuivantàlafonction.
Faites attention aux opérateurs d'affectation. Ce ne sont PAS des signes decomparaison!(Pourcomparer,c'est==.)
AUTOETVOLATILE
Citonsdeuxmotsclésliésauxvariables,maissansapprofondir:
auto(commedansautofloatsalaire; )estunvestigedulangageB
quiaservid'inspirationauC.EnB,unevariable localeàune fonctionn'était
pas automatiquement automatique. Le C n'a pas besoin de ce qualificateur,
mais son successeur, le C++ en a profité pour réutiliser auto pour son
nouveaumécanismededéductiondutype.
volatile(commedansvolatilefloatsalaire;)intéresseceuxqui
écrivent des programmes très techniques par exemple pour piloter les
échangesentrelesystèmeetunpériphérique(cléUSB,disquedur,etc.),c'est-
à-diredespilotes.Eneffet,silavariableestvolatile,celasignifiequesavaleur
peutchangersansqu'aucuneinstructiondevotreprogrammeneledemande,
doncqu'unautreprogrammeyaaccèsaussi.Cela impliquedeprendredes
précautions.Personnen'aimequel'ondéplacesesaffairesensonabsence.
Avoirlebraslong:variablesglobalesUnevariabledéclaréeendehorsdetoutblocdefonction,ycomprisendehorsdublocde la fonction principalemain(), est accessible en lecture et en écriture depuisn'importe où dans le mêmemodule de code source (le même fichier), à conditioncommepourtoutevariablequ'elleaitétédéclaréeavantdel'utiliser.
C'estpourquoi lesvariablesglobales sont regroupées toutaudébutdu texte source,avantladéfinitiondelapremièrefonction(engénéral,main()).
Unevariableglobaleestlisibleetmodifiabledepartout
Intéressons-nousaucodesourcesuivant.Ilillustrel'utilisationd'unevariableglobalepourunepetitepartiedeping-pong:
LISTING9.5Textesourcedef_pingpong.c
//f_pingpong.c
#include<stdio.h>
#defineNBR7
//Variableglobale
charballes=NBR;
//Prototypesdefonctions
charping(char);
charpong(char);
//Programmeprincipalmain()
intmain()
{
charechanges=0;
//Projetf_pingpong.c!
echanges=ping(balles+1);
//Findepartieapresxechanges
return0;
}
//Joueurlanceur
charping(charlancer)
{
lancer--;
if(lancer>0){
//AffichagePingballex(lancer)
lancer=pong(lancer);//APPELPONG
}
if(lancer==1){
//AffichageVictoiredePing!
return(lancer);
}
return(lancer);
}
//Partenaire
charpong(charrenvoyer)
{
//renvoyer++;
if(renvoyer>1){
//Affichage...etPongx(renvoyer)
ping(renvoyer);//APPELPING
}else{
//Affichage...Pongratelaballe
return(renvoyer);
}
return(renvoyer);
}
L'exécution laisse voir un amusant échange entre les deux fonctions ping() etpong() : voici comment notre journaliste sportif, Monsieur printf(), acommentélematch:
Projetf_pingpong.c!
//Pingballe7…//...etPong7
!
//Pingballe6…//...etPong6
!
//Pingballe5…//...etPong5
!
//Pingballe4…//...etPong4
!
//Pingballe3…//...etPong3
!
//Pingballe2…//...etPong2
!
//Pingballe1…//...Pongrate
laballe
VictoiredePing!
Findepartieapres7echanges.
Cet exemple permet de voir comment des actions dumonde physique peuvent êtreincarnéespardesalgorithmes.
L'exemple est biaisé puisque celui qui a le service gagne toujours. La fonctionping() appelle pong() qui appelle ping() alors que nous avions appelépong()del'intérieurdeping()!Cettecascadesepoursuitsursixniveauxpuispong() rate la balle. Tous les retours d'appels en attente sont alors exécutés enrafale.Nousprenonssoinden'afficherlemessagedevictoirequepourunniveauderetour.(Vouspouvezétablirundiagrammedufluxd'exécutionsurpapierlibre.)
Lesexpertsverrontvitedespossibilitésd'optimisation.Rappelonsquel'exempleestàviséepédagogique.
Lepont-levisdemain()Nous avons dit que main() était spéciale au niveau des paramètres. Vous êtesautoriséàladéfinirsoit:
» sansaucunparamètre(),commenousl'avonsfaitjusqu'ici;
» soitavecdeuxparamètres,maisleurtypeetleurnomsont
imposés.Danscecas,latêtededéfinitiondemain()seprésente
ainsi:
intmain(intargc,char*argv[])
Vous ne décidez pas de la valeur du premier paramètre. Du fait que la fonctionmain() est appelée par le système lorsque vous demandez le démarrage duprogramme, le système analyse la ligne de commande (même via une icône, vouspouvezdéfinirdesparamètressurlaligneenaccédantauxpropriétés).
Silesystèmetrouveautrechosequelenomduprogramme,commedesoptions,illesdénombreencherchantlesespacesséparateurs(voilàpourquoiilestdéconseillédelaisser des espaces dans les noms de fichiers, utilisez plutôt le caractère desoulignementquiapresquelamêmeapparence).
Aprèsavoircomptélesparamètres(certainsdisentarguments),lenombreeststockédansleparamètreargc(ARGumentCount)ettouslesparamètressontstockésdansunestructurededonnéesdetypetableaunommeargv[](structurequenousallonsdécouvrirdansleprochainchapitre).Lamentiondetypespécialchar*signifiequevous obtenez l'adresse du premier élément du tableau, pas sa valeur (tout vas'éclaircirdansquelquespages).
Sivousdémarrezunprogrammeainsi:
f_pingpong17score.txt
vous demandez le démarrage du programme f_pingpong en lui demandant detravailler avec 17 balles et d'écrire les messages dans un fichier texte dont vousfournissezlenom.
Lavariableargccontiendraicilavaleur3(lenomduprogrammeeststockéaussi,carilestparfoisutiledesavoirdel'intérieurcommentons'appelle).
Biensûr,ilfautdanscecasmodifierlatêtedemain()etajouterdes instructionspourlirelesvaleursdepuisletableau.
Voyons pour finir cet intense chapitre la technique qui a rendu fou plus d'unprogrammeur. Nous ne ferons que jeter un rapide regard, car la récursion peutaisémentdonnerletournis.
Jesous-traiteàmoi-même!RécursionPuisqu'unefonctionpeutenappeleruneautre,pourrait-onpousserlalogiquejusqu'àdemanderàlafonctiondes'appelerelle-même?
Osonsaborderleconceptderécursiondansunlivrepourdébutants.N'avez-vouspasenviedeconnaîtrel'ivressedesprofondeurs,sansvousmouiller?Allons-y.Oui,celavachatouillerlesneurones,etc'estbon.
//f_recursi.c
#include<stdio.h>
#defineLIMITE19
intcompter(intiVarDeb);
intmain(){
compter(1);
}
intcompter(intiVarDeb)
{
//AffichagedeiVarDeb
if(iVarDeb<LIMITE){
compter(iVarDeb+1);
}
//AffichagedeiVarDeb
return(iVarDeb);
}
Lecentred'intérêtestdanslafonctioncompter():
intcompter(intiVarDeb)
{
//
if(debut<LIMITE){
compter(debut+1);
}
TantquelavaleurdeiVarDebestinférieureàlalimite(définieparunedirective#definecommeégale à 19), nous appelons la fonctioncompter() alors quenoussommesencoredanscettefonction!C'estcelalarécursivité.
Unefoisarrivéauplafond,touslesappelsretournentenreprenantàlalignequisuitl'appelimbriqué,cequifaitaffichertouteslesvaleursdanslesensdécroissant.
L
Chapitre10Donnéesstructurées[]
DANSCECHAPITRE:
» Donnéessimplesetcomposites
» Tableauxetlistes
» Leschaînesanglaises,strings
eprécédentchapitrenousapermisdedécouvrirleprincipalmoyend'organiserlesactionsd'unprojetenblocsautonomesquisont les fonctions.Pour l'instant,nousn'avonsmanipuléquedesdonnéessimples,c'est-à-diredesdonnéesdontleformat
peutdirectementêtrerapportéàlafaçondontsontconfigurésélectriquementlesbitsdanslescircuitsduprocesseuretdelamémoire.
Nousavonsvulalargeurdumotmachine(parexemple32ou64bits)quicorrespondautypeentierdebasenomméint,etnousavonsvusesvariantes (char,short,long et long long). Pour les valeurs non entières, nous avons vu les typesfloatetdoubleetleurcodagescientifiqueIEEE754.
Dans un traitement numérique, il est souvent nécessaire d'appliquer le mêmetraitementàplusieursnombresoude regrouperplusieursvaleursdansunmêmesacsansperdrelapossibilitéd'accéderàchaquevaleurindividuelle.
LeCoffredeuxsolutionspourconstruiredespaquetsdedonnées:
» letableaupourregrouperplusieursdonnéestoutesdumême
type;
» lastructurepourregrouperplusieursdonnéesdetypesdivers,
maisnousverronslesstructuresdansledernierchapitredecette
partie.
Encequiconcernelestableaux,nousallonsvoirleursdeuxutilisationsprincipales:
» pourstockerdesvaleursnumériquesentièresouflottantes;
» pourstockerdestextes,phrases,messagesentantquechaînesde
valeursdutypechar.
UngroupedevariablesanonymesVous vous souvenez que nous pouvons donner un nom à un bloc d'actions pour enmarquerledébutavecuneétiquettesuivid'unsignedeux-points.
Le tableau permet un peu lamême chose, mais pour regrouper des données. Voicid'abordcommentdéclarersuccessivementcinqvariablesentièresenleurfournissantunevaleurinitiale:
intmaVar1=10;
intmaVar2=21;
intmaVar3=32;
intmaVar4=43;
intmaVar5=54;
Si nous avons besoin d'augmenter chaquevariable d'unemêmevaleur, nous devonsécrirecinqinstructions:
intaugmentation=1;
maVar1=maVar1+augmentation;
maVar2=maVar2+augmentation;
maVar3=maVar3+augmentation;
maVar4=maVar4+augmentation;
maVar5+=augmentation;//Tournureabrégée
Trèsrépétitif.Mêmeunprogrammeurdébutantdevinerapidementqu'ildevraityavoirunesolutionplusélégante.
Il suffit d'accepter de perdre la relation individuelle avec chaque variable enmanipulantlesdonnéesparlebiaisd'unnuméroentierservantd'indice.
Unpeucommepouruntroupeaudechèvres:au-delàd'unecertainetailledetroupeau,lefermiernepeutplussesouvenirduprénomdechacune.Neplusconnaîtrechacundesesvoisinsestaussicequimarquelafrontièreentrevillageetville.
Dresseruntableau
Le terme«dresser» est approprié, car le tableauest un animal farouche.Tous lesdébutantsenconviennent.
Le terme anglais pour ce conteneur à données estarray que l'on traduit depuis lesdébutsentableau.Maisuntableauestunesurface,souventrectangulaire,doncavecune largeur et une longueur. Pourtant, comme vous allez le voir, la majorité destableaux n'ont qu'une dimension. D'ailleurs, le terme array se traduit aussi paragencement ou arrangement. Les tableaux simples que nous allons voir sont doncplutôt des listes de valeurs. Certains parlent de vecteurs pour les tableaux à unedimension,etdematricespourlesautres.
Pourconstruire(déclarer)uneséquencedevariablesanonymesenC,vousutilisezlescrochets droits à la suite du nom de la variable collective.Mais puisque c'est unevariable,ilfauttoujoursindiqueruntypededonnéeavantlenom.
nom_typenom_tableau[];
C'estlesquelettefondamental.Vousrépondezensuiteàtroisquestions:
» Est-cequejeconnaisdèsledépartlenombred'élémentsà
regrouperdansletableau,mêmesansenconnaîtrelesvaleurs?
» Est-cequejeconnaisdéjàtouteslesvaleursinitialesdeces
données?
» Est-cequejeconnaisdéjàaumoinsunevaleurinitiale?
TableaucréépleinLorsque vous connaissez les valeurs initiales de toutes les variables, cela voussimplifie la création du tableau. Vous utilisez une paire d'accolades (tiens, lesrevoici!)etlistezlesvaleursenlesséparantparunevirgule:
intmonTabRempli[5]={10,21,32,43,54};
Riennevousinterditbiensûrdemodifierensuitecesvaleurs.Nousverronscomment.
Lamentionduchiffre5entrecrochetsestfacultative,maisvouspouvezl'indiquersicela vous aide. En effet, l'analyseur (l'outil de traduction de code source en codemachine,quifaitpartieducompilateurquenousutiliseronsdansleprochainchapitre)peutdéduirelatailledutableauencomptantlenombredevaleursfournies.
FIGURE10.1:Implantationmémoired'untableau.
Une fois le tableau ainsi peuplé, il occupe de l'espace en mémoire et devientutilisable.
TableaucrééamorcéLorsquevousconnaissezunevaleurinitialepourlapremièrevariable,vouscréezletableauainsi:
intmonTabVar[5]={1};
Touteslesautresvaleursserontdeszéros,cequiestmieuxquerien.
Tableaucréévide
intmonTabVar[5];
Cette déclaration provoque la création d'un espace mémoire réservé pour cinqvariablesanonymesdutypeint.Vousdisposezensuitedecinqcasesouconteneurs,maisvousn'yavezencorerienstocké.
Une fois la déclaration faite, vous ne devez plus jamais accepter de voir cechiffre5(ouunautre)entrelescrochetsdecetableau!Jamaisplus!
TABLEAUFUTURINTERDIT!
Untableaufutur?Oui,unnomdetableauassociéàuneseulecasemémoire
de la taille demandée, mais rien d'autre. C'est ce que vous espérez obtenir
lorsquevousnefournisseznilataille,niaucuncontenu.
shortmonImpossibleTabFutur[];
Cette déclaration est refusée par un message : array size missing…
(dimensiondutableaunonspécifiée).
Enrevanche,vousavezledroitdecréerunpointeurversuntableaudecettemanière,maislespointeurssontunsujetdélicatdontnousverronslesgrandeslignesplustard.
Utilisez-le,[maintenant]!Vous n'exploitez pas le contenu d'un tableau comme une variable simple. Vouspouvez:
» lirelecontenu;
» écriredanschaquecase(modifier);
» fairevoyagertoutletableau(letransmettred'unefonctionàune
autre);
» fairevoyagerlecontenu.
Quelle que soit la façon dont vous avez peuplé votre tableau, c'est pour en fairequelquechose.Repartonsdutableauprérempli.Nousutilisonslanotationindicéeenindiquantlenumérodelacelluleàlire,encommençantàzéro:
LISTING10.1ExtraitdufichiertabRempli.c
intmonTabRempli[5]={10,21,32,43,54};
intmaVar;
maVar=monTabRempli[0];
//Premierelement,monTabRempli[0]=10
maVar=monTabRempli[1];
//Deuxiemeelement,monTabRempli[1]=21
maVar=monTabRempli[2];
//Troisiemeelement,monTabRempli[2]=32
maVar=monTabRempli[3];
//Quatriemeelement,monTabRempli[3]=43
maVar=monTabRempli[4];
//Dernierelement,monTabRempli[4](PAS5!)=54
Pour l'exemple, nous écrasons le contenu demaVardès que nous l'avons utilisé.Vous pouvez bien sûr utiliser une variable à la place du chiffre d'indice. Cettetechniqueesttrèsutiliséedansuneboucle.
Itérons,petitpataponVoyonscommentlirelesmêmesvaleursdansuneboucle:
//LecturedemonTabRemplidansuneboucle
for(i=0;i<5;i++){
//AffichagedemonTabRempli[i]
}
//monTabRempli[0]10
//monTabRempli[1]21
//monTabRempli[2]32
//monTabRempli[3]43
//monTabRempli[4]54
C'est presque toujours de cette façon que les tableaux sont utilisés.Voici commentmodifierlescontenusdeséléments:
//Modificationdela4èmevaleurdemonTabRempli
monTabRempli[3]=298;
//monTabRempli[3]contientlavaleur298
LepointsurlesindicesC'estune incohérenceapparentedu langageC:sivousavezbesoindestockercinqvaleurs,vousdevezeffectivementindiquerlechiffre5pourdéclarerletableau.
Enrevanche,lesnumérosd'ordredeséléments(leursindices)commencentàzéro,etnonà1.Ledernierélémentdutableau,lecinquième,estdoncceluiàl'indice4.Celaexpliquequelaconditiondepoursuitedeboucles'écrive:
i<5;
EnlangageC,zéroestlepremierindice!
L'humainatendanceàcommenceràcompteràun.Pourtant,zéroestunchiffre!
Vousaimezlehors-piste?LelangageCquisertdesupportàcettedécouverteimposepeuderègles.Auniveaudes tableaux, il n'y a aucunmécanismedeprotection contre les sorties de piste. Sivouscréezuntableaudecinqéléments,lelangageCnevousinterditpasdedemanderlecontenuduonzième.
Dansl'exemplesuivant,noussortonsdepisteàdeuxreprises.
LISTING10.2TextesourcetabHorsPiste.c
//tabHorsPiste.c
#include<stdio.h>
intmain(void)
{
inttablox[5]={10,21,32,43,54};
intmaVar;
maVar=tablox[0];
//Premierelementtablox[0]=10
maVar=tablox[5];
//Nouspassonsenhors-pisteavectablox[5]:0
maVar=tablox[11];
//Plusloinavectablox[11]quicontient:3873265
return0;
}
Lecontenumémoiredesendroitsdemandésest sansaucunesignificationpourvous.Enlecture,cen'estpastrèsgrave,saufsivousbasezlasuiteduprogrammesurcequevousvenezdelire.
FIGURE10.2:Lecturehorstableau.
En écriture, il est extrêmement dangereux de modifier une valeur en dehors de lastructure. C'est une technique radicale pour bloquer le programme. Les systèmesmodernes possèdent des mécanismes de protection mémoire qui vous empêchentd'écrireailleursquedansleszonesréservéesauxdonnées,maiscelanegarantitpasqu'iln'yaurapasdedommagesencasdehors-piste.
En effet, un tableaun'est qu'une suite d'emplacementsmémoire adjacents (dumoinspourchaquedimension).
&:l'adressemémoired'untableauLenomdutableauestunevariablespécialequicontientl'adressedupremierélément(c'estunpointeur).Envoicilapreuveavecl'opérateur&quivientenpréfixedunomdeconteneuràlocaliser:
LISTING10.3ExtraitdufichiertabAdresse.c
inttablox[5]={10,21,32,43,54};
intmaVar;
maVar=tablox;
//Valeurdunomtableau?:2686732
maVar=&tablox[0];
Adressedetablox[0]?:2686732
Lavaleurfluctued'uneexécutionàl'autre.C'estuneadressemémoire.
L'intelligence du tableau permet d'utiliser des indices pour aller d'un élément ausuivant en ajoutant un à l'indice, mais le langage traduit ce saut d'indice en sautd'adresseappropriégrâceautypededonnée.Voiciunexemple:
» partonsduprécédenttableaudecinqentiersint
(chacun4octets);
» pourallerdel'élément0àl'élément1,l'indiceaugmentede1;
» l'élémentoccupequatreoctetsenmémoire,doncsonadressede
départetlestroissuivantes;
» ilfautavancerdequatreunités(quatreoctets),doncdel'adresse
de0àl'adresse+4.Cettemultiplicationestautomatique.
La fin du texte source tabAdresse.c montre comment utiliser un pointeurvolontairement sous-dimensionné pour illustrer le mécanisme d'accès. Nousconseillonsd'avoirlulafindecettepartiedulivreavantdel'étudier.
EnfinuntableautabulaireVoici un tableau digne de ce nom avec une longueur et une largeur, donc à deuxdimensions.
LISTING10.4Extraitdufichiertab2D.c
inttTab2D[3][5]={{11,21,31,41,51},
{12,22,32,42,52},
{13,23,33,43,53}};
Observezbienledoublejeud'accolades:
» unjeud'accoladespourlaglobalitédutableau;
» unjeuintérieurpourchaquecontenud'unexemplairedela
premièredimension;
» desvirgulesentrelesvaleurs.
Le principe de peuplement consiste à indiquer pour la première ligne toutes lesvaleursdelasecondedimension,puisdemêmepourleslignessuivantes.
Voyonscommentaccéderauquatrièmeélémentdelatroisièmeligne(valeur43).Vousdevez désigner la ligne d'indice 2 (la troisième) et la colonne d'indice 3 (laquatrième).Vous pouvez recopier ce contenu dans une variable temporaire du typeappropriéainsi:
tempo=tTab2D[2][3]);
//Affichagedetempo,soit43
Voicienguisedecomparaisonladéclarationd'untableaude5lignesde3éléments,soitl'inverseduprécédent:
inttTab53[5][3]={{11,21,31},
{12,22,32},
{13,23,33},
{14,24,34},
{15,25,35}};
Voicicomment lire lecontenudupremierélémentdechacunedescinq lignesdecetableau:
for(tempo=0;tempo<5;tempo++)
maVar=tTab53[tempo][0]);
//AffichermaVar
sizeof():l'empreintemémoired'untableauVous voudrez parfois connaître la taille réelle d'un tableau, c'est-à-dire le nombred'octetsquesesélémentsoccupentenmémoire.
Il suffitd'appliquer l'opérateursizeof()aunomdu tableau (sansaucun indice).Appliquons-leàtroisdestableauxprécédents:
LISTING10.5TextesourcetabTaille.c
//tabTaille.c
#include<stdio.h>
intmain(void)
{
shorttailleTA,taille2D,tailleTC,tempo;
shortmonTabAmorA[5]={12,21,32,43,54};
doublemonTabAmorC[128]={14.0};
inttTab2D[3][5]={{11,21,31,41,51},
{12,22,32,42,52},
{13,23,33,43,53}};
tailleTA=sizeof(monTabAmorA);
tempo=tailleTA/sizeof(short);
//monTabAmorAoccupe10octetspour5elements
short.
tailleTC=sizeof(monTabAmorC);
tempo=tailleTC/sizeof(double);
//monTabAmorCoccupe1024octetspour128elements
double.
taille2D=sizeof(tTab2D);
tempo=taille2D/sizeof(int);
//tTab2Doccupe60octetspour15elementsint.
return0;
}
Pourchaquetableau,nousnousservonsdeuxfoisdel'opérateursizeof().D'abordpourconnaîtrelataillehors-toutdechaquetableau,expriméeenoctets:
tailleTA=sizeof(monTabAmorA);
Lepremiertableaucontenantcinqélémentsdetypeshort(nousavonschangésontypedepuisleprécédentexemple),l'occupationmémoirebruteestégaleà10(5x2).
Retrouverlenombred'élémentsestensuiteunjeud'enfants:
tempo=tailleTA/sizeof(short);
Pourquoidemandons-nouslatailledutypestandardshort?Toutlemondesaitquec'estledeuxièmepluspetitconteneuràvaleur:deuxoctets.
Supposons que vous ayez écrit un programmepour un processeur qui utilise quatreoctetspourletypeintetdeuxoctetspourletypeshort.Vousvoulezréutiliserleprogrammesurunautomateindustrieldanslequelletypeintestsurdeuxoctetsetle typeshortsurunseul.Sivous indiquezunevaleur littérale fixepour la tailleunitaire,tousvoscalculsdetailledetableaux(etd'autres)serontàreprendre.
Ilestdoncconseilléd'interroger lamachinepourconnaître la tailledechaquetype,carellen'estpasstandardisée.Lesdeuxtypesintetlongoccupentparfoisdeuxoctets,parfoisquatre(parfoismêmehuitpourlong).
Lecalculestlemêmepourlesdeuxautrestableaux.
» monTabAmorCétantuntableaudevaleursdécimalesdouble,
chacuneoccupe8octets.
» tTab2Destnotrevraitableauendeuxdimensions.
Cette technique ne permet pas de retrouver la structure d'un tableau à plusieursdimensions. Un tableau contenant deux lignes de six éléments occupera le mêmeespacequ'untableaudetroislignesdequatreéléments.
LestableauxdynamiquesLorsque vous ne pouvez pas prévoir la taille maximale du tableau, l'approchegrossièreconsisteà«voirlarge».Maisvousrisqueztoujoursdeprovoquerunhors-pistesilesbesoinsdestockagedépassentvotrelargevision.
La solutionexiste : le tableaudynamiquequecertainsnommentunvecteur.Pourenprofiter,ilfautd'abordapprendreàutilisertroisfonctionsprédéfiniesdontlesnomssont malloc(), realloc() et free(). Elles permettent de réservermanuellementdel'espacemémoirependantl'exécution.Lesutilisersupposedesavoirmanierlespointeurs,cequenousverronsdansl'ultimechapitredecettepartie.
Pourlemoment,essayonsdeconstruireunhyper-tableau,untableauquel'onnepeutmêmepasdessinerdansnotreuniversphysiquequin'aquetroisdimensions(oui,plusletemps).
UnprojetdanslacinquièmedimensionOn veut gérer deux indicateurs d'activité pour les techniciens d'une entreprisepétrolière.
» L'entrepriseestimplantéedans2zonesd'exploitation.
» Chaquepaysestdécoupéaumaximumen3régionsouzones.
» Chaquezoneregroupeaumaximum5sitesouplates-formes.
» Chaquesiteoccupeaumaximum8techniciens.
» Àchaquetechniciensontassociés2indicateursd'activité(heures
sursite/heureshorssite).
Chaqueidentificateurestunefeuilledel'arbre.C'estlàquesontstockéeslesvaleurs.
Le typeint suffira pour stocker nos indicateurs d'activité. Les indices sont desvaleurs croissantes qui ne dépasseront jamais les bornes. Le type char suffiraitdonc,mais nous allons opter pourint, car certains outils analyseurs se plaignent.Commentdéfiniruntableaupourgérertoutcela?
inttabH[2][3][5][8][2];
C'estlatechniquedebase.Nousrendonsladéclarationbienpluslisibleendéfinissantdes symbolesavecdesdirectives#defineendébut de texte.Ces symboles (parconvention,toujoursécritsenmajuscules)serontremplacésparlavaleurindiquéeenéquivalence:
#definePAYS2
#defineZONE3
#defineSITE5
#defineTECH8
#defineIDEN2
Unefoisceséquivalencesdéfinies,lacréationdutableaupeuts'écrireainsi:
inttabH[PAYS][ZONE][SITE][TECH][IDEN];
Pour éviter que le tableau contienne des valeurs aléatoires (ce qui se trouve à cetendroitdanslamémoireàcemoment),nousdemandonsd'écrirelavaleur1danslapremièrecase.D'office,touteslesautrescasesrecevrontlavaleur0,cequipermetdecommenceravecuncontenudetableaupropre:
inttabH[PAYS][ZONE][SITE][TECH][IDEN]={1};
Notretableauvacontenir2x3x5x8x2,soit480éléments.Chaqueélémentestdetype entier signé. Sur un ordinateur personnel récent, ce type de données occupequatreoctets(32bits).Letableauvadoncoccuper4x480,soit1920octets.
Voyons l'exemple complet dans une première version avec très peu d'affichages. Ils'agitvéritablementd'unestructureàcinqdimensions(d'oùlenomdel'exemple).
LISTING10.6Exempledetableauàcinqdimensions(tab5D.c).
//tab5D.c
#include<stdio.h>
#definePAYS2
#defineZONE3
#defineSITE5
#defineTECH8
#defineIDEN2
intmain(void)
{
intident=0;
inti,j,k,l,m=0;
inttabH[PAYS][ZONE][SITE][TECH][IDEN]={1};
for(i=0;i<PAYS;i++){
for(j=0;j<ZONE;j++){
for(k=0;k<SITE;k++){
for(l=0;l<TECH;l++){
for(m=0;m<IDEN;m++){
ident++;
tabH[i][j][k][l][m]=ident;
}
}
}
}
}
return0;
}
Après ladirectived'inclusiondestdio.h, indispensable pour pouvoir utiliser lafonctiond'affichageprintf()quenousdécouvrirons enfin dansquelquespages,nous trouvons nos cinq définitions de symboles avec la directive#define. Puisnousentronsdanslecorpsdelafonctionprincipale(etuniqueici).
Nousdéclaronsseptvariablesentroislignes:
intident=0;
inti,j,k,l,m=0;
inttabH[PAYS][ZONE][SITE][TECH][IDEN]={1};
D'abordunentier isoléquirecevrauncompteurafind'inscrireunevaleurdifférentedanschaquecellule,cequiservirad'identifiantunique.
Ladeuxièmelignedéclared'untraitcinqvariablesquiserventd'indicespourlescinqdimensionsdutableau.Nouschoisissonsletypeint.Aucunindicen'iraplusloinquelavaleur7:c'estlavaleurmaximalepourlaquatrièmedimensionTECH(souvenez-vous,lehuitièmeélémentcorrespondàl'indice7).
La troisième ligne déclare notre tableau géant. Nous utilisons les cinq symbolesprévus.L'outilquivaconstruire le fichierexécutable (lecompilateur)vavoir cetteligneinterprétéecommececi:
inttabH[2][3][5][8][2]={1};
La valeur entre accolades est l'astuce qui permet d'amorcer l'écriture d'une valeurconnue dans toutes les cellules (de peupler le tableau avec une valeur initiale quiest0,saufdanslapremièrecellulequicontiendra1).
Certainscompilateursémettentunavertissement(bénin)devantcettemanièred'écrireaumoinsunevaleur initialedansunecellule. Ilestvraiqu'ilyacinqdimensionsàindiquer. Si ce message vous gêne, vous écrivez ceci pour avoir les cinq pairesd'accoladesqueréclamel'analyseur:
={{{{{1}}}}};
Une fois ces préparatifs terminés, nous plongeons dans une formidable cascade decinq boucles imbriquées. Ici, l'intérêt d'une bonne présentation est évident. Lesindentations laissent comprendre immédiatement l'imbrication. Voici une versionallégée:
for(){
for(){
for(){
for(){
for(){
//ACTIONS;
}
}
}
}
}
Vous remarquez que l'accolade ouvrante d'un niveau est placée sur la ligne del'instructiondebouclealorsquel'accoladefermantequiluirépondestseulesuruneligne,alignéeaveclepremiercaractèredecetteinstruction.C'estunemanièred'écriretrès répandue.Enoutre,nousavonschoisideuxespacesd'indentationàcausede lalargeur de ligne disponible dans ce livre. En pratique, on utilise souvent quatreespaces.
Danschaquebouclefor,nousfaisonstroischoses:
indice=0;indice<MAXDIM;indice++
1. Nousdécidonsdelavaleurinitialeducompteurdetoursde
boucle.Nouscommençonsbiensûrà0afindepouvoiraccéder
aupremierélémentdeladimension.
2. Nouschoisissonsquelleconditiondoitêtresatisfaitepour
commencerletoursuivant.Ici,labutéeestladimension.En
choisissantd'arrêterdèsquelecompteurn'estplusinférieur,
nousatteignonsbienledernierélément(celuid'indice2pour
untableaudetroisélémentscommeZONEdansl'exemple).
3. Nouspassonsàlacellulesuivanteparincrémentationde
l'indice.Rappelonsque:
nomvar++
estuneversionabrégéede:
nomvar=nomvar+1;
Arrivé au fond du tableau, au niveau le plus profond (indicem), nous stockons lavaleurdel'identifiant:
tabH[i][j][k][l][m]=ident;
Dansl'exemple,nousnouscontentonsd'augmenterde1cetidentifiantparident++,mais on pourrait prévoir à cet endroit un appel à une fonction pour lire la valeurdepuisunfichierdisque(ouendemanderlasaisie,maissaisir480valeurssansfairedepauseseraitunpeuinconfortable).
Il ne reste plus qu'à refermer les cinq blocs conditionnels imbriqués par une joliecascaded'accoladesfermantes.
Voicilemêmeexemplequipermetdevoiràl'écranqueleprogrammefaitbiencequiestprévu.Pourladernièrefoisdanscelivre,nousévitonsdeprésenterlesappelsàlafonction d'affichage standardprintf() et les remplaçons par des commentaireséquivalents.
LISTING10.7Exempledetableauàcinqdimensions(tab5Daff.c).
//tab5Daff.c
#include<stdio.h>
#definePAYS2
#defineZONE3
#defineSITE5
#defineTECH8
#defineIDEN2
intmain(void)
{
intident=0;
inti,j,k,l,m=0;
inttabH[PAYS][ZONE][SITE][TECH][IDEN]={1};
for(i=0;i<PAYS;i++){
//PAYS:i
for(j=0;j<ZONE;j++){
//P:iZONE:j
for(k=0;k<SITE;k++){
//P:iZ:jSITE:k
for(l=0;l<TECH;l++){
//P:iZ:jS:kTECH:l
for(m=0;m<IDEN;m++){
ident++;
tabH[i][j][k][l][m]=ident;
//ValeurpourIDEN:m
//tabH[i][j][k][l][m]);
}
}
}
}
}
//tabHoccupe1920octets
return0;
}
Voiciledébutdes480élémentsaffichés:
PAYS:0
P:0ZONE:0
P:0Z:0SITE:0
P:0Z:0S:0TECH:0
ValeurpourIDEN:0=1ValeurpourIDEN:1=
2
P:0Z:0S:0TECH:1
ValeurpourIDEN:0=3ValeurpourIDEN:1=
4
P:0Z:0S:0TECH:2
ValeurpourIDEN:0=5ValeurpourIDEN:1=
6
P:0Z:0S:0TECH:3
ValeurpourIDEN:0=7ValeurpourIDEN:1=
8
P:0Z:0S:0TECH:4
ValeurpourIDEN:0=9ValeurpourIDEN:1=
10
P:0Z:0S:0TECH:5
ValeurpourIDEN:0=11ValeurpourIDEN:1
=12
P:0Z:0S:0TECH:6
ValeurpourIDEN:0=13ValeurpourIDEN:1
=14
P:0Z:0S:0TECH:7
ValeurpourIDEN:0=15ValeurpourIDEN:1
=16
P:0Z:0SITE:1
P:0Z:0S:1TECH:0
//etc.
Letableauestdoncuntypededonnéecomplexeindispensable,maisiln'acceptequ'untype d'élément à la fois.Nous verrons en fin de partie une technique plus évoluée,permettantde combinerdesdonnéesde typesdifférentsdansune structuregrâce aumotcléstruct.
Mais voyons d'abord un domaine d'utilisation a priori étonnant et pourtant trèsrépandudestableaux:leschaînesdecaractèresoustrings.
Amessageinthetableau:leschaînesÀl'origine,lelangageCn'avaitpasétéconçupour«fairelaconversation»,c'est-à-direpourafficherdesquestionsetdesréponsessurunécranpourqu'unutilisateurlesliseetpourrécupérercequ'ilsaisitauclavier.
Rappelonsquec'estenlangageCqu'estécritcequiestunmonumentd'ingénierie:lesystème d'exploitation Unix, et donc aussi Linux et MacOS. L'ensemble du codesource deLinux représente environdixmillions de lignes (sans les commentaires),dont à peu près 95% sont enC. Environ 70% des serveursWeb dumonde connufonctionnentgrâceàcesmillionsdelignesdeC.
Un systèmed'exploitation est peu bavard. Il est très occupé à gérer lamémoire, leprocesseur,lesdisques,lesconnexionsréseau,etc.
Ces origines expliquent qu'en langage C, presque rien n'était prévu au départ pourstocker des phrases, desmessages, des dialogues dans un langage humain.D'autreslangages disposent d'un mot clé du style « string » ou « text » pour définir puismanipulerunesériedelettresdel'alphabet,dechiffresetdesymboles.EnC,c'estleminimumsyndical:les26lettresdelalanguedesdescendantsd'Européensquisontallésfairefortunedanslesgrandesplainesd'Amérique.
Nous avons vudans la partie 1 que l'alphabet anglais était depuis les années 1960codéenbinaireselonlanormeASCII:
» leschiffresde0à9correspondentauxvaleursdécimales45à54;
» leslettresAàZmajuscules(valeursdécimales65à90);
» leslettresaàzminuscules(valeursdécimales97à121);
» descodesspéciauxcomplètentlapanoplieentre1et31,puisdes
signesde32à44etdanslesautrestrousjusqu'à127.
Il s'agit ici de l'ASCII debase, reconnupar tous les ordinateurs de l'univers.Danscettesection,nousnenousintéressonsqu'àcejeudecaractèresaméricain.
Vous savez que le plus petit type numérique entier en C est char. Il correspondà8bitsetpermetdemémoriserunevaleurparmi256sinonsigné(unesur127s'ilestsigné).
UntableaudevaleurscharOnpeutbiensûrcréeruntableaudevaleurschar.Regardezcetextrait:
charsMsg[11];
sMsg[0]=80;
sMsg[1]=114;
sMsg[2]=111;
sMsg[3]=103;
sMsg[4]=114;
sMsg[5]=97;
sMsg[6]=109;
sMsg[7]=109;
sMsg[8]=101;
sMsg[9]=122;
sMsg[10]=0;
Maisstop!Procédonsàunappeldesous-programmedanslalecturedulivre.Nousreviendrons à notre tableau juste après. L'heure est venue de dévoiler celle qui secachedepuiscentpages:printf().
Enfinlafonctionprintf()Pourmanipuler desmessages lisibles par des hommes, il faut les leurmontrer. Latechniquefondamentalequandontravailleenmodetexte(modeConsoleouTerminal,doncnongraphique)reposesurunefonctionpolyvalented'affichage:printf().
C'est une fonction standard, fournie avec tous les compilateurs pour le langage C.Pourpouvoirl'appeler,ilfautdonclafaireconnaîtreàl'analyseur.Sonprototypesetrouvedansunfichierd'en-tête(fichierseterminantpar.h)portantlenomdefichierstdio.h. La seule précaution consiste à ajouter une directive en tout début de textesource pour faire analyser d'abord ce fichier standard (il est situé dans un sous-dossierquel'analyseursaitlocaliserautomatiquement,sitoutestbienconfiguré).
Ceciexpliquel'ajoutdecetteligneaudébutdequasimenttouslesexemples:
#include<stdio.h>
Unefoiscelafait,lafonctionprintf()estaccessible.Soncodeexécutabledéjàtraduit se trouve dans un fichier de librairie, lui aussi localisé automatiquement.Pratique,non?
La fonction printf() est beaucoup plus riche que d'autres, en termes depolyvalence.Elle comporte des dizaines d'options, des formateurs de contenus, descaractères de format d'affichage, et surtout, elle est à géométrie variable (elle estvariadique).Nousallonsladécouvriraufuretàmesuredesbesoins.
Voicisasyntaxeformelle.
printf("texteavec%xet\y",
nomvariable)
La fonction renvoie le nombre de caractères qu'elle a affichée plus un. Dans leprochainexemple,nousl'utilisonsdeplusieursmanières.
Maintenantquenousdisposonsdecetoutild'investigationprintf(),vérifionsdansune boucle avec un compteur ce qui a été stocké dans le tableau sMsg[] crééquelqueslignesplushaut:
LISTING10.8L'exemplecompletst1_tab.c,avecsesappelsàprintf().
//st1_tab.c
#include<stdio.h>
char*ptr_sAnglaise;
intmain(void)
{
charsMsg[11];
sMsg[0]=80;
sMsg[1]=114;
sMsg[2]=111;
sMsg[3]=103;
sMsg[4]=114;
sMsg[5]=97;
sMsg[6]=109;
sMsg[7]=109;
sMsg[8]=101;
sMsg[9]=122;
sMsg[10]=0;
printf("Baptemed'appeldeprintf()!\n");
chari;
for(i=0;i<11;i++){
printf("%d\t",sMsg[i]);
}
printf("\n");
for(i=0;i<11;i++){
printf("%c\t",sMsg[i]);
}
return(0);
}
FIGURE10.3:Untableauchaîne.
Uneséquenced'échappement:\nAprès déclaration et peuplement du tableau, nous trouvons notre premier appel àprintf():
printf("Baptemed'appeldeprintf()!\n");
Dans cet appel, la fonction ne reçoit qu'un seul paramètre (ou argument).C'est unechaîne de caractères littérale, délimitée par des guillemets. Elle se termine par unméta-caractère(lecouple\n)quin'estpasaffiché.Ilprovoquelepassageàlalignesuivantepourlasuitedel'affichage.
Cecouplesenommeuneséquenced'échappementparcequ'iléchappeàl'affichage.
Unformateur:%dAprèsavoirdéclaréunevariablecompteurdeboucle,nousentronsdansunepremièreboucle pour demander à la fonction standard printf() d'afficher la valeurnumériqueluedanschaquecelluledutableau.
printf("%d\t",sMsg[i]);
Nousutilisonsicideuxautresmétacaractères,leformateur%detlaséquence\tquiprovoqueunsautdetabulation.Leformateurcommencetoujoursparlesymbole%.Lalettredsignifiedécimal.Cesdeuxcaractèressontremplacésdansl'affichageparlavaleurdusecondparamètre(aprèslavirgule)aprèsconversiondecettevaleurenunesériededessinsdechiffreslisibles.
Sachant cela, le résultat de ces onze appels àprintf() pourrait vous dérouter(nousavonsréduitlalargeurdessautsdetabulationpourtenirsurunelignedulivre):
80114111103114971091091011220
Lafonctionaconvertilavaleurnumérique80trouvéedansletableauenunesuitededeuxcaractèresaffichables8et0puisaamenélecurseurdepositiond'affichageaupasdetabulationsuivant.Riendecequisetrouvaitdanslepremierparamètredelafonctionn'estdirectementvisibledanslerésultat.
Nousexpliquonsplusloinlaraisond'êtredelavaleurzéroendernièreposition.
Jusque-là,toutestnormal.Noussavonsdéjàcequec'estqu'untableau:unelistedevaleurstoutesdumêmetype.Quelrapportavecnoslangageshumains?
Magieduformateur%cEtmaintenant,untourdemagie.Nousarrivonsàunesecondebouclequiestpresqueune copie conforme de la première. La seule différence : dans les paramètres deprintf(),nousremplaçonsleformateur%dparsoncollègue%c:
printf("%c",sMsg[i]);
Essayonsleprogramme.Voicicequis'affiche:
Programmez
Cemotétaitcachédansletableau!Lescaractères,chiffresetlettresn'existentnullepartdansl'ordinateur.Ilneconnaîtquedesoctets.
Le formateur %c demande à la fonction printf() d'afficher littéralement legraphique(unglyphe)delalettrequicorrespondàlavaleurnumériqueselonlatablede caractères en vigueur (ici, c'estASCII).D'une certaine façon, cela lui demandemoinsde travail qued'afficher lesvaleursnumériques (un seul signevisuel au lieude2ou3).
En effet, quand vous demandez d'afficher avec %d (ou un autre formateur noncaractère),lafonctiondoitfaireuneconversiondumêmestylequenouslorsquenousavonsàécrireunesommeentouteslettressuruncontratouunecaution:
...lasommede3230(TROISMILLEDEUXCENTTRENTE)
euros.
Lorsqueprintf() reçoit par exemple le nombre 102 à traiter avec%d, il doitafficher lecaractère1,puis lecaractère0puis lecaractère2 (alorsqu'avec%c, ilaffichedirectementlalettrefminuscule).
Pourspécifierunechaînelittérale:""Déclarer une chaîne de message en écrivant une par une les valeurs ASCII descaractèresdansuntableauestloind'êtrepratique.LeCafaitunpetitgestepournousaider:lachaînelittérale.Nousl'avonsvueplusieursfoisdéjàsansenparler.L'heureestvenue.
Il suffit de placer du texte entre deux délimiteurs identiques qui doivent être desguillemetsdroits:
"Mignonne,allonsboire"
"silevinestfrais."
Lerésultatestuntableauouunechaînestatique.
Unpetitsouci:enfrançais,onusedesguillemetsdroitspourles«citations».Facile,il suffit d'utiliser un caractère spécial (un métacaractère) qui est la barre obliqueinverseouantibarre:
"Onaimeles\"citations\"danslestextes."
Combiend'auteursdelivresd'informatiquefrançaisontdécouvertavecstupeurqu'unefois leur livre mis en page et imprimé, tous les guillemets droits sont devenustypographiques(«»)etlesapostrophessontbalancés,gaucheetdroite(´`).Non,nonetnon. Il faut leguillemetdroit, de codeASCII34, et l'apostrophedroite, de codeASCII39.
Ilestdoncpossibledegagnerdutempsenécrivantlachaînelittéralement,maispourstockercettesériedevaleursnumériquesdéguiséesdansunevariable,cettevariabledoitêtredetypetableau.
LISTING10.9L'exemplecompletst2_ronsard.c
//st2_ronsard.c
#include<stdio.h>
intmain(void)
{
charsRon[]="Mignonne,allonsboire";
charsSard[]="silevinestfrais.";
charsCita[]="Onaimeles\"citations\".";
printf("%s",sRon);
printf("%s",sSard);
printf("\n\n%s",sCita);
}
Voiciunedestroisdéclarationsdevariableschaînesdel'exemple:
charsSard[]="silevinestfrais."
Les trois instructions d'affichage utilisent un nouveau formateur,%s. Ces signifiestring,chaînedecaractères.Voicilapremièrelignequis'affiche:
Mignonne,allonsboiresilevinestfrais.
Puisquenousvoulonsrabouterlesdeuxpremierstableaux,nousaurionspuremplacerlesdeuxinstructionsparcelle-ci,d'autantquenousavonsprévuunespaceséparateuràlafindelapremière:
printf("%s%s",sRon,sSard);
Dans le troisième appel àprintf(), le premier paramètre qui est la chaîne deformatagecomportedeux fois lemétacaractèrede sautde ligne (npourNew line).Observezbienletraitementappliqué.Enpartantdececi:
printf("\n\n%s",sCita);
lafonctionprintf()synthétiseuntableaudecaractèresuniquecontenantdeuxfoisle code numérique du saut de ligne (non imprimable ici), un espace puis la chaîneaprèssuppressiondesanti-barres,chaînequiremplaceleformateur%s:
Onaimeles"citations".
Tailledestableauxchaîne
L'outil de construction (le compilateur) sait compter le nombre de caractères pourdimensionner chaque tableau. Le premier tableau de l'exemple fera 23 caractèresutilesdelongetl'autre20.
Mieux encore, il va ajouter une cellule tout à la fin des tableaux pour y écrire lavaleurnumérique0.Les tableauxferontdonc24caractèresde long(23signeset lezéroterminal)et21(20+1).Pourquoi?
Mêmes'ilfaitsemblantaveclafacilitéd'écritureci-dessus,leCnesaitpascequ'estune phrase, un mot, bref du texte. Il ne voit que des chiffres comme prouvé dansl'exempleprécédent.Etsurtout,rienn'estprévupourmémoriserlalongueurdechaquechaîne.
L'astucechoisieconsisteàréserverlavaleurzéropourmarquerlafindutableaudecaractères.Devantunechaînelittéraleentredélimiteurs,leCajouted'officecezéroterminallorsqu'ilstockelachaînedansletableaurécepteur.LerésultatestunechaîneàzéroterminalouchaîneAZT.
Cela répond à la question laissée en suspens dans le premier exemple de tableauchaîne (le mot caché Programmez). Comme nous avions construit la chaînemanuellement en peuplant un tableau élément par élément, aucun mécanismeautomatiquen'auraitajoutél'arrêtoirpournous.C'estpourquoinousavionsterminélacréationdutableaupar:
sMsg[10]=0;
Chaîne=tableaudechar+zéroterminal
DeschaînesAZTpartout!Lorsque vous utilisez un tableau de chiffres comme le gros tableau d'exemple del'entreprise pétrolière quelques pages plus haut, vous restez attentif aux bornes dutableau. Vous n'allez pas puiser des valeurs en dehors du tableau, car vous savezqu'ellesn'ontaucunsens (etquec'estdangereuxdegambaderailleursdans l'espacemémoire).
Avec leschaînesde texte, c'estdifférent.Leshumainsne s'intéressentpasàchaquecaractèredechaquemotd'unephrase.
Les textes doivent donc souvent être manipulés sous forme de tableaux entiers(affichés,transmis,dupliqués,tronqués,scrutés).Parcommodité,cestableauxchaînessont presque toujours créés à partir de chaînes littérales.Le zéro terminal est doncajoutéd'office.Maisencorefaut-ilpenseràtestersaprésence!
Savez-vousplanterunordi?C'est une des erreurs les plus fréquentes que de vouloir travailler avec une chaînesansarrêtoir,carlesfonctionschaînestravaillentenbouclejusqu'àdétecterlavaleurzéro.Siellen'estpastrouvée,leprogrammeestenpéril.
Lorsque vous avez besoin de lire un tableau chaîne élément par élément, placezl'actiondansunecondition:
while(tablo[i]!=0){
ACTION;
i++;
}
S'il n'y a aucun élément dans le tableau ayant la valeur zéro, ceci est une boucleinfinie!C'estencoreduhors-piste,maistoutdroitdansleravin.
UnflorilègedefonctionschaînesLa librairie standard duC propose une famille complète de fonctions chaînes pourvousfairegagnerdutempsaveclestableauxchaînes.Toutesdépendentdelaprésencedelabutéedefindetableau,c'est-à-direduzéroterminal.Ellesnedigèrentbienqueles chaînesAZT.La valeur que renvoient la plupart de ces fonctions est hautementestimable.Vousdevezdonclacapterdansunevariable.
Ces fonctions ne sont pas définies dans lamême librairie queprintf(). Il fautdoncajouterunesecondedirectived'inclusionendébutdefichierpourlesutiliser:
#include<string.h>
Voiciunaperçurapidedequelquesfonctionsdédiéesàlamanipulationdetableauxdecaractères:
Concaténationstrcat(tabDest,tabSrc)
Rienàvoiravecunchat,mêmeanglais.LetermecatvientdeconCATéner,prochedecaténaire,c'est-à-direformerunechaîne(àpartirdedeux).
CettefonctionajoutelecontenudutableautabSrcàlafindutableautabDestetrenvoietabDest.
Recherched'uncaractèrestrchr(tabScrute,intcarac)
Recherche la première occurrence du caractère dans le tableau et renvoie la sous-chaînecommençantàsaposition.
Comparaisondetextesstrcmp(str1,str2)
Comparedeuxchaînesetrenvoieunevaleurnégativesilapremièreestantérieureàl'autre (dans l'ordre des valeurs croissantes des codes ASCII). Ainsi, "aBC" estinférieurà"Ayz".
Duplicationstrcpy(tabDest,tabSrc)
Copie le tableau tabSrc dans le tableau tabDest avec le ZT et renvoietabDest.
Mesuredelongueurstrlen(tabTexte)
Renvoielalongueurdelachaîne,noncomprislezéroterminal.
Expulsiond'unechaînesimpleputs(tabTexte)
Cettefonctionest lapetitesœurdeprintf().Elleenvoievers lecanaldesortiestandard (l'écran en mode texte) la chaîne sans appliquer aucun traitement (elle
n'accepteaucunformateur%,niséquenced'échappement\).Enrevanche,elleajouted'officeunsautdeligneàlafin.
Pourmieuxconnaîtrecesfonctions,ilestbond'avoirpriscontactavecleconceptdepointeurquenousverronsenfindepartie.
Lepointessentielestcelui-ci:toutescesfonctionsdépendentdelaprésenced'unzéroterminalenfindechaîne.Nel'oubliezjamais.
Avoirl'accentanglais?Voiciunpetitexemplequiselimiteàvouloirafficherundébutdephraseenfrançais,doncavecquelquesaccents:
LISTING10.10Testst5_accents.c
//st5_accents.c
#include<stdio.h>
intmain(void)
{
charsEte[]="\nL'âmeestsûreaudébutde
l'été…";
printf("%s",sEte);
}
Ce programme est prévu pour s'exécuter en mode texte, donc dans une fenêtre determinal.SousWindows,voilàcequipeutapparaître:
FIGURE10.4:AffichagedelettresaccentuéesfrançaisesdansleterminalWindows.
IlyadoncunpetitsouciquigêneautantlesQuébécoisquelesMétropolitains.Toutcequine faitpaspartiedu jeudecaractèresaméricain risquedesubircegenrede
mésaventure. Si vous utilisez Linux ou MacOS, leur choix de UTF-8 devraitsupprimerlesouci(àconditiond'enregistrerletextesourcedansceformat).
UnicodeetUTFDanslesenvironnementsgraphiqueshabituels(Windows,MacOS),unesolutionaétémiseenplace,maiselleestdifférentedanschaquecas.
La solution définitive et universelle se nomme Unicode. Cette norme existedepuis1991etdonneunnuméroàchaquesymboledecaractèreetd'idéogramme,ycomprislesrunesdesvikings(cesontdesglyphes,commeleshiéroglyphes).Unicodecodeactuellementplusde centmille éléments.Le soucide l'applicationdeUnicodeestqu'ilyaplusieursmanièresdecoderlesglyphes:
» soittoujourssur4octets,c'estlecodageUTF-32;
» soitsur2octetsetparfois4,c'estlecodageUTF-16adoptépar
Windows;
» soitsur1à4octets,c'estlecodageUTF-8,systématisésousUnixet
LinuxetqueMacOSreconnaîtaussi.Presquetouslessiteswebde
nosjoursfonctionnentenUTF-8.
En langage C, un type de caractère étendu a été proposé en 1990, le « caractèreélargi»(widechar),maissalargeurn'estpasfigée.Surlesordinateursdebureau,ilpeutcorrespondreàdeuxouàquatreoctets.Surunmicrocontrôleurdelave-vaisselle,le caractère élargipeut se réduire àunoctet, cequipermet aumoinsd'afficher lesaccentseuropéensdanslesmessagesàl'utilisateur.Bref,cetypenerépondpasbienauproblème.
En2011,leCetleC++ontproposédeuxtypesélargisclairementdéfinis.Cesontlestypeschar16_tetchar32_t.Ilspermettentdestockerdescodagessur16ou32bitsdesglyphesUnicode.
Encequi concerne cetteprésentationdes chaînes, sachezqu'àpartir dumomentoùchaque caractère est codé sur plus d'une valeur de type char, les fonctionsclassiques quimanipulent ces tableaux de caractères sont perdues. EnUTF-8, le aminuscule américain correspond àun seul octet,mais le e accent gravedu françaisvaennécessiterdeuxet leslettresducoréencomme vontoccuperdeuxoutroisoctets.
Conclusion
Ilnous reste àdécouvrirunautre typededonnéescomplexe (la structure)qui, à ladifférencedutableau,permetdemélangerdestypesdifférents.Celaferal'objetd'unautrechapitre.
Nousavonsdécouvertunnombre suffisantdenotionspour faireunepausedans lesconnaissancesdulangage.Voyonscommentconstruiredesprogrammesutilisablesparl'ordinateur(exécutables)àpartirducodesourcequevousavezécrit.
S
Chapitre11Leprocessusdeconstruction
DANSCECHAPITRE:
» Fichiersource,codeobjetetexécutable
» Fichiersd'en-tête
» Préprocesseur,compilateur,assembleur,lieur
» Découverted'unatelierdeconstruction(Code::Blocks)
ivousavezlulesprécédentschapitresdecettepartie,vousavezunebonnevisionglobale des fondamentaux d'un langage de programmation, en l'occurrence lelangage C. Rappelons que le C est un langage compilé, c'est-à-dire qu'il faut
fournirletextesourceàunoutilquival'analyserpourproduireunfichierbinaire.
Avant de découvrir quelques autres concepts indispensables (les structures et lespointeurs), nous pouvons faire une pause dans cette visite d'un langage pour nousintéresseràlamanièredefabriquerunprogrammeàpartirdecequevousécrivez.
Ceprocessusnedemande aucun effort devotrepart ; ce sont desoutils qui font letravailunefoisquevousleuravezdonnéquelquesprécisions.
Pourillustrerlasuite,nouspartonsnonpasd'untextesource,maisdedeux:
» unmoduleprincipalcontenantmain()et
» unsatellite.
Voicilemoduleprincipal:
LISTING11.1TextesourcecompletdefoncModule1.c
#include<stdio.h>
externvoidmaFoncNue(char);
intmain()
{
printf("Avantd'appelermaFoncNue!\n");
maFoncNue(0);
printf("\nRevenudemaFoncNue!***\n");
return0;
}
La fonctionmaFoncNue() est déclarée et utilisée mais son corps de définitionn'estpasprésent!Leprototypeindiqueextern,cequiprévientl'analyseurquec'estnormal.Elleestdéfiniedansunautretextesource.
Voicicesecondmodule:
LISTING11.2TextesourcecompletdefoncModule2.c
//foncModule2.c
#include<stdio.h>
voidmaFoncNue(charval)
{
if(val==0){
printf("\nDansmaFoncNue!***\n");
}
}
Revoicilepremiercodesourcetelquevouslerédigezdansunéditeurdetexte:
FIGURE11.1:Vueducodesourcedansunéditeurdetexte.
Et voici un aperçu du fichier exécutable .EXE qui va en résulter s'il n'y a pasd'erreur:
FIGURE11.2:Extraitducodeexécutablecorrespondant.
Bien sûr, le fichier .EXE n'est pas fait pour être chargé dans un éditeur de texte,puisquec'estunesuitedecodesmachines.Néanmoins,onpeutydistinguerleschaînes
decaractèresdesdeuxfichiersdedépart.
La taille du fichier source foncModule1.c s'élève à 211 octets alors que celle dufichier exécutable foncModule1.exe correspondant est de 55 272 octets, soit plusde 200 fois plus. C'est remarquable, d'autant qu'un état intermédiaire du fichier, lefichier assembleur (Figure11.3) n'occupe que 665 octets et reste lisible (quand onconnaîtlelangageassembleur).
FIGURE11.3:Codeassembleurintermédiaire.
Dans le code source, nous ne trouvons que quatre instructions : deux appels à unemême fonction standard d'affichage (printf()), un appel à une fonction externemaFoncNue()etunreturnpourterminerpolimentl'exécution.
Enenlevanttouslesappelsàprintf(),ondescendà23Ko,maisc'estencorecentfoislevolumeinitial.Quesepasse-t-il?
Le fichier .EXE contient des informations techniques indispensables pour que lesystème sache implanter le programme en mémoire et préparer son exécution puisréaliser des actions de maintenance (libération de la mémoire notamment) en find'exécution.Les30Kodeplusdelaversioncomplètesontdoncimputablesaucode
de la fonction standardprintf()quenousutilisons.Elle adoncété injectée enpartiedanslecode.
LesquatreétapesdelaconstructionIlsepassebeaucoupdechosespendantlaconstructiondel'exécutable.Leprocessusfaitintervenirtouràtourquatreoutils:
» lepréprocesseur;
» lecompilateur;
» l'assembleur;
» lelieur.
Vouspouvezconstruireunexécutablededeuxfaçons:
» Soit«àlamain»,surlalignedecommandeenmodetexte(dans
unefenêtredeterminal).Danscecas,vousdevezconnaître
quelquesoptionspourdirigerlestravaux.Nousdonneronsles
commandesàsaisirpourlacollectiond'outilsGCC.
» Soitdansunatelierdedéveloppementenmodegraphique.En
général,lesoptionsadéquatessontdéjàréglées,maisilestutilede
savoircequisepasse.Nousverronsdansunesectionultérieure
commenttravailleravecCode::Blocks,unatelierdedéveloppement
gratuit.
Dès qu'un projet dépasse de l'ordre d'une centaine de lignes, le code source estnormalementdistribuédansplusieursfichierssourceoumodules.Lestroispremièresétapes de la construction s'appliquent à chaque module source jusqu'à obtenir unfichierdecodeobjet(extension.o).Lelieurréuniralesfichiers.opourconstruireununiquefichierexécutable.
FIGURE11.4:Étapesdeconstructiond'unprogrammeexécutable.
Voyons ces quatre étapes l'une après l'autre en prenant comme outil la collectiond'outilsMinGWbasée surGCC (GnuCompilerCollection).GCC est un ensembled'outilslibresdontnousexpliquonsl'installationenannexe.
1)PréprocesseurNous savons que pour pouvoir utiliser une fonction prédéfinie standard, il fautindiqueraucompilateur lenomd'unfichiercontenant leprototypedecettefonction.Dansl'exemple,c'étaitladirectivetoutendébutdefichiersource:
#include<stdio.h>
Lesfichiersd'en-tête.hLorsqu'ilrencontreunedirectived'inclusion,lepréprocesseurvachercherlefichierindiquéetinsèretoutsoncontenuàlaplacedeladirective,quidisparaît.
Voiciuntrèscourtextraitdufichierstdio.hdelavarianteMinGWducompilateurCpourWindows.Lefichiercompletcompte650lignes:
#undef__mingw_stdio_redirect__
#define__mingw_stdio_redirect__(F)__cdecl
__MINGW_NOTHROW__mingw_##F
externint__mingw_stdio_redirect__(fprintf)(FILE*,
constchar*,...);
externint__mingw_stdio_redirect__(printf)(const
char*,...);
L'extrait est choisi puisqu'on peut voir le prototype de la seule fonction qui nousintéresseparmiles41fonctionsprédéfiniesdanscefichierd'en-tête.
L'extrait précédent « pique un peu les yeux » , mais vous devriez commencer àdistinguerlesmotsclésetlesidentifiants.
Nousreconnaissonslemotcléexternquiprévientquelafonctionprintf()esteffectivement définie ailleurs, en l'occurrence dans une librairie. Cette déclarationexterne empêche le compilateur de se plaindre qu'il n'a pas trouvé les instructionsd'une fonction. Quand on oublie une telle mention, on obtient un message dans cestyle:
undefinedreferenceto'nomFonction'
L'autreopération importanted'unfichierd'en-têteest le remplacementdessymbolesdes directives#define. Il s'agit d'un remplacement systématique du symbole parsonéquivalent.Sivousécrivezcettedirective:
#defineTEMP_MAX95
à tous les endroits dans le code sourceoù le préprocesseur détecte lemotTEMP_MAX,illeremplaceparlavaleur95.C'esttrèspratiquepourcentraliserunevaleurconstantequevousenvisagezdemodifier.
Rappelonsquelesnomsdessymbolesde#defines'écriventenmajuscules.
Pour l'essentiel, une fois les inclusions et les remplacements faits, le fichierintermédiairequiestproduitestprêtàpasseràl'étapesuivante:lacompilation.
Les fichiers d'en-tête contiennent aussi des directives conditionnelles dont nous neparleronspas,tellesque#ifdefet#ifndef.
Quellecommande?Pourobtenir le résultatdu travaildu seulpréprocesseur, lacommandese fonde surl'option-E(enmajuscule):
gcc-EfoncModule1.c-ofoncModule1.i
Vousadaptezlacommandeaunomdevotrefichiersource.
2)CompilateurL'outildecompilationestundesgrosmorceauxdecetteséried'outils.C'estpourcetteraisonqueleterme«compiler»estdevenusynonymedelatotalitéduprocessusdeconstruction.Souvent,on«compile»unprogramme,puisonle«recompile»aprèsavoircorrigéuneerreur,maiscompilern'estqu'unedesétapesdelaconstructionquiproduitunfichierexécutable.
Ilfautdirequelecompilateurabeaucoupàfaire:
» Ildoitanalyserscrupuleusementlecodesourcepours'assurerqu'il
comprendtout.
» Siaumoinsuneerreuraétédétectée,leprocessuss'arrête.Inutile
depoursuivre.
» S'ilaundoute(sansquecesoituneerreur),ilémetun
avertissement(warning).
» S'iln'adétectéaucuneerreur,lecompilateurproduitunfichier
restantlisibleparleshumains:ducodeassembleur.
Larigueuraveclaquellevotrecodesourceserajugéestréglable(option-Wallpourunerigueurmaximale).
Prenonsl'exemplepédagogiquesuivant:
unsignedintmaVarUtile=12;
unsignedintmaVarInutile=14;
voidmain(){
maVarUtile=48;
return;
}
Nous déclarons deux variables,mais nous n'utilisons jamais la seconde ! Pourquoialors la déclarer ? Le compilateur s'en aperçoit et peut émettre une remarque à cesujet.Celanevapasempêcherdeproduirelecodeobjet,maisc'estétonnant.Àvousdevoir.
Revenonsànosdeuxmodules.
Quellecommande?Pour obtenir le résultat du travail du seul compilateur, la commande se fonde surl'option-S(enmajuscule):
gcc-SfoncModule1.i
Vousadaptezlacommandeaunomdevotrefichiersource.
Vous obtenez un fichier à extension .s (comme aSsembleur) déjà aperçu enFigure11.3.C'est toujoursducodesource,maisdanslelangageleplusélémentairequiexiste,directementconvertibleencodemachinebinaire:
LISTING11.3CodeassembleurintermédiairefoncModule1.s
.file"foncModule1.c"
.def___main;.scl2;.type32;.endef
.section.rdata,"dr"
LC0:
.ascii"Avantd'appelermaFoncNue!\0"
LC1:
.ascii"\12RevenudemaFoncNue!***\0"
.text
.globl_main
.def_main;.scl2;.type32;.endef
_main:
LFB6:
.cfi_startproc
pushl%ebp
.cfi_def_cfa_offset8
.cfi_offset5,-8
movl%esp,%ebp
.cfi_def_cfa_register5
andl$-16,%esp
subl$16,%esp
call___main
movl$LC0,(%esp)
call_puts
movl$0,(%esp)
call_maFoncNue
movl$LC1,(%esp)
call_puts
movl$0,%eax
leave
.cfi_restore5
.cfi_def_cfa4,4
ret
.cfi_endproc
LFE6:
.def_puts;.scl2;.type32;.endef
.def_maFoncNue;.scl2;.type32;.endef
Mêmesans rienconnaîtreau langageassembleur,onpeut retrouver sanseffortsnosappelsdefonction(engras),saufquecesontdorénavantdesinstructionscall.
NousvoyonsnotreidentifiantdefonctionmaFoncNue,maispourquoicesmentionsputslàoùnousdemandionsd'appelerprintf()?
La fonction standardprintf()est sophistiquéepuisqu'ellepermetd'injecterdesvaleurs dans une chaîne servant demodèle grâce à des spécificateurs basés sur lesigne %. En revanche, puts() est élémentaire. Elle envoie vers la destinationchoisie (écran, fichier, connexion réseau) une chaîne sans aucun traitement. Voilàpourquoi, une fois la chaîne définitive construite, il ne reste plus qu'à utiliserputs().
Cecodeassembleurpeutêtreconvertiencodeobjetparleprochainoutil.
3)AssembleurApartirdecemoment,votreticketn'estplusvalable!Lerésultatdecetteétapeestunfichier dont le contenu est devenu quasiment illisible. Ce sont des instructionsmachine,doncdifférentesselonletypedeprocesseur(Intel/AMDoubienARMparexemple).
Quellecommande?
Pour obtenir le résultat du travail du seul assembleur, la commande se fonde surl'option-c(enminuscule):
gcc-cfoncModule1.s
Vousobtenezunfichieràextension.o(commeObjet).C'estdevenuducodepresqueexécutable.Presque?
Ilmanque tous les liensavec les fonctionsextérieuresaumodule :maFoncNue()del'autremoduledansnotreexemple,etcellesdelalibrairiestandard,printf().
Cettemiseenrelationestletravailduquatrièmeetdernieroutil,lelieur.
Sivousréalisezleprocessusdeconstructionétapeparétapecommenousvenonsdele montrer, il faut maintenant réaliser les trois étapes précédentes pour le secondmoduleafindedisposerdefoncModule2.o.
4)LieurLe lieur est le couturier de l'informatique. Il tisse les liens entre les appels defonctionsetlesfonctionsappeléesd'unmodulesourceàunautre.Ilajouteaussidesinstructionsàexécuteravantledémarrageduprogramme(prologue)etd'autresaprèssonexécution(épilogue).
Pour les fonctionsprédéfiniesdes librairies, il injecte le codedes seules fonctionsutilisées dans le fichier résultant oumême seulement un lien (adresse). Sans entrerdanslesdétails,sachezqu'ilexistedeuxsortesdelibrairies:
» leslibrairiesstatiques(fichiers.aou.lib):lecodedesfonctionsest
effectivementtotalementrecopiédansvotreprogramme,cequile
rendautonome,maisiloccupeplusd'espaceenmémoirequandil
fonctionne;
» leslibrairiesdynamiques(.DLLsousWindows,.soou.dylibsous
Unix):lelienn'estpasrésoluparlelieur,maispendantl'exécution,
cequipermetàplusieursprogrammesd'appelerlemême
exemplaireducodedelafonctioncommune.
Dans les deux cas, les librairies sont différentes selon le système d'exploitation,notammentlalibrairiegénéraledontlenomdefichiercontientsouventleslettresCRT(pour Common RunTime). Sous Windows, cette librairie sera par exempleMSVCRT.DLL.
Quellecommande?Pourobtenirlerésultatfinalàpartirdesfichiersencodeobjet,lacommandeutilisel'option-o(minuscule)pourpréciserlenomdésirépourlefichierexécutable:
gcc-onomprogfoncModule1.ofoncModule2.o
Vousobtenezlefichierexécutablenomprog.exe.
L'intérêtdeprésentercesopérationsélémentairesuneparuneestsurtoutpédagogique,mais il estparfoisutiled'allervoircommentchaqueoutilacomprisvotre intentioninitiale.
Les outils de production se conforment à un jeude règles qui varie d'un système àl'autrenotammentpourdéfinirlafaçondontsontmisenplacelesappelsdefonctions.C'estl'ApplicationBinaryInterface(ABI).
ConstructionenuneétapePour créer en une seule commande le programme précédent constitué de deuxmodules, il suffit de spécifier le nom de sortie avec -o et les noms des modulessource:
gcc-onomProgfoncModule1.cfoncModule2.c
Vousobtenezdirectementleprogrammeprêtàl'emploi!
FIGURE11.5:Exempledesessiondecompilationavecgcc(premièreligne).
Constructionautomatisée(make)Dèsqueleprojetdevientimposant(denombreuxmodulesetlibrairies),unpetitrobotpeutréaliserletravailàvotreplace.
Eneffet, lorsquevousmodifiezunfichiersource, ilest inutilederegénérer tous lesautresfichiersdecodeobjet.Ilsuffitderetraiterlefichiermodifiépuisderelancerlaseuleétapefinaledulieur.
L'outil nommémake (construire) puise ses instructions dans un fichier texte (unfichiermakefile) qui définit toutes les règles de dépendance en remontant depuisl'exécutablejusqu'auxfichierssources.Lenomdefichierdoits'écriremakefileetlefichiernedoitpascomporterd'extensiondenom.Ilnepeutdoncexisterqu'untelfichierdanschaquedossier.
LISTING11.4Exempledefichierd'automatisationmakefile.
all:foncModule.exe
foncModule.exe:foncModule1.ofoncModule2.o
gcc-ofoncModule.exefoncModule1.o
foncModule2.o
foncModule2.o:foncModule2.c
gcc-cfoncModule2.c
foncModule1.o:foncModule1.c
gcc-cfoncModule1.c
net:
delfoncModule1.ofoncModule2.ofoncModule.exe
Lesrèglessontlesnomssuivid'unsignedeux-points.
Leslignesenretraitsontdescommandes.L'indentationdoitabsolumentêtreproduiteparlecaractèredetabulation,surtoutpaspardesespaces.
SousLinux/MacOS,lacommanded'effacementdeldoitêtreremplacéeparrm.
L'utilisation du robot de construction est très simple, puisqu'il suffit d'indiquer sonnom:
make
L'outilcomprendquevousvoulezfairereconstruiretoutleprojetdepuisledébut.SivousfaitesuneretouchedansfoncModule2.c,vousdemandezdenereconstruirequecettepartie:
makefoncModule2.o
Dans notre petit exemple, cela ne fait pas de différence, mais lorsque le projetcomprend des dizaines de fichiers source, le gain de temps est énorme et vous nerisquezpasd'oublierdementionnerunfichierouuneoption.
Cegenrederobotesttrèsutiliséparexemplepourlesgrosprojetsdedéveloppement.Une reconstruction complète est lancée en fin de journée de travail. Ce procédécorrespondauxNightlyBuilds(reconstructionsnocturnes,commelecorpshumain).
UnatelierdedéveloppementVoyons maintenant comment travailler avec la souris. Enfin, direz-vous. Maisn'oublions pas que programmer c'est concevoir des solutions et les écrire. Unprogrammeurutilisebeaucoupsonclavier.
Cette section va utiliser un outil gratuit et très répandu qui fonctionne sur les troisplates-formes Linux, MacOS et MS-Windows. Cet outil se nomme Code::Blocks.NousabrégeronsenCBdanslasuite.
Nouspartonsdel'étatinitialdeCB(Figure11.6).Sivousvoulezpratiquercequisuit,voyezd'abordenannexecommentinstallerl'outil.
FIGURE11.6:VueinitialedeCode::Blocks.
Démarraged'unnouveauprojetOuvrezlemenuFichieretlesous-menuNouveau.VouspouvezchoisirProjet.
Uneboîtededialogueapparaît.Vousfiltrezleschoixensélectionnantdanslalistelacatégorie Console. Vous pouvez alors sélectionner le type de projet Consoleapplication.
FIGURE11.7:MenuFichier/Nouveau.
LetermeConsolevientdufonddesâgesde l'informatique.Sur lesgrosordinateursquirégnaientdanslesannées1960-70,lesutilisateursseconnectaientviaunterminal,un descendant du Téléscripteur. Un seul poste était relié directement à la machinedans la même salle. Certaines opérations très techniques n'étaient possibles quedepuiscetteconsoleprivilégiée.LetemeConsoleestrestépourdésignerunefenêtre(ouunplein-écran)enmodetexte.
FIGURE11.8:Choixdutypedeprojet.
ValidezparleboutonAller(ouGo,lelibellépouvantêtreenanglaisouenfrançaisselonlaversiondel'atelierinstallée).
Vousarrivezàuneétapetrèsbrèvedechoixentredeuxlangages.
FIGURE11.9:ChoixdulangageC.
Pardéfaut,onvousproposed'utiliserlelangageC++.Changezcetteoption,puisquenosprojetssontenlangageC.Validezparleboutonenbasàdroite.
L'étapesuivanteméritetoutevotreattention.Ils'agitdedéciderdunomduprojetetdel'emplacementdesfichiers.
FIGURE11.10:Choixdunomduprojetetdesonemplacement.
Dansl'exemple,nousavonsindiquélenomconstruction.NousavonsaussiprévuundossiernomméCODEBLOKdanslequelserontcrééstouslesautresprojets(saufaviscontraire).
Choisissez un autre nom et un autre emplacement si vous savez le faire. Sinon,acceptezl'emplacementproposésurvotresystème.
Inutiled'intervenirdanslesdeuxautreschampsdesaisie.ValidezparleboutonNextouSuivant.
L'étapesuivanteesttrèsintéressante,carvouspouvezychoisirvotrepanoplied'outilsdeconstruction,c'est-à-diresurtoutvotrecompilateur,doncvotrelangage.
Siellenel'estpasencore,cochezlacasedel'optionCréerlaconfigurationdeDebug. L'autremode,Créer la configurationdeRelease, est normalementdéjàcochée.
FIGURE11.11:Choixducompilateuretdesconfigurations.
Maisqu'est-cequesignifientcestermes?
» Torelease,c'estlibérer,diffuser.Danscettevariante,la
constructionvaaboutiràunfichierexécutableprévupourêtre
distribué,venduoudonné,installé,afinqu'ilrendeserviceaux
utilisateurs.
» Todebug,c'estmettreaupoint,déboguer.Danscettevariante
«interne»,laconstructionvaaboutiràunfichierplusgros,dans
lequelsontinjectésdessymbolespourlesvariablesetlesfonctions.
Cessymbolessontinutilesaubonfonctionnementnormaldu
programme,maisilsserventàunoutilnommédébogueurpour
vousaideràtrouverleserreursdansleprogramme.Laversion
Debugn'estdoncpasdestinéeàêtrerenduepublique,d'autantque
lefichierestplusvolumineux.
Nous demandons de générer les deux variantes. Si vous voulez explorer lespossibilitésdedébogage,ilvousfautcettevariantetechnique.
LalisteCompilateurenhautmérited'êtreconsultée.Vouspouvezychoisirvotrepanoplie d'outils de construction, c'est-à-dire surtout votre compilateur, donc votrelangage.
FIGURE11.12:Aperçuduchoixdecompilateurspossibles.
CequiestproposépourunprojetdetypeConsoleconvientparfaitement(GNUGCCCompiler). La lecture de la liste vousmontre que vous pouvez créer des projetspourd'autrestypesdeprocesseursquelesIntel/AMDdenosPCetMac:
» lesprocesseursARMsonttrèsutilisésdansleséquipements
électroniques(telliphones,tablettes)etlescartesdecontrôlepour
larobotique(commelacélèbrecarteRaspberryPi);
» lesmicrocontrôleurs(commelafamille8051)serventdansle
mondeindustriel.
Il y a même des options pour travailler en Fortran, le langage scientifique desannées1960,toujoursutilisédanslarecherche.
Conservons le choix GNU GCC puisque les outils correspondants sont installésd'officeenmême tempsque l'atelierCode::Blocks, sivousavez installé lavarianteMinGW(celaestdétailléenannexe).
Vous pouvez valider par le boutonTerminer (ouFinish). Vous allez maintenantentrerdansvotrenouveauprojet.Vousrevenezdanslafenêtreprincipale.
Regardez le volet situé à gauche, affichant normalement le contenu de l'ongletProjets.C'estunelistehiérarchisée.
FIGURE11.13:LevoletProjetsavecleprojetdéplié.
1. Utilisezleboutondedépliementdesdétailspourfaire
apparaîtrelabrancheterminalequiaétécrééed'officepourle
fichiersourceprincipaldetoutprojetC.
2. Cliquezunefoisdanslenommain.cpourlesélectionnerpuis
cliquez-droitpourouvrirlemenulocaletsélectionnezEnlever
lefichierduprojet.
Vouspartezainsid'unprojetvraimentvide.
ApportdesfichierssourcesL'étape suivante est particulière. En temps normal, vous partez du fichier minimalpréinséré(main.c)etvousrédigezvotrecodesource.
Dansnotreexemple,nousdisposonsdéjàdedeuxfichierssources.Sivousréalisezcetutoriel,vousaurezrécupérécesfichiersavectouslesautrescodessourcesdulivre,commeindiquéenannexe.
Nousallonsdoncdéposerlesdeuxfichiersdansledossierduprojet(quenousavonschoisidenommerconstruction).
Utilisez l'Explorateur de fichiers ou le Finder pour copier les fichiers. RevenezensuitedanslafenêtredeCode::Blocks.
Danslevoletgauche,cliquez-droitsur lenomdeprojetconstructionetchoisissezAjouterdesfichiers.Danslaboîtededésignationdefichiers,naviguezjusqu'audossierduprojet etmulti-sélectionnez lesdeux fichiers (dansnotre exemple, ils senommentfoncModule1.cetfoncModule2.c)puisvalidez.
Pourmulti-sélectionner,maintenezenfoncéelatoucheCtrltoutencliquant.
FIGURE11.14:Boîtedesélectiondesfichiersàajouter.
Dès que vous validez, une boîte d'options vous demande de confirmer que vousvoulezproduirelesdeuxvariantesReleaseetDebug.Confirmezsansrienchanger.
FIGURE11.15:BoîtedechoixdesvariantesReleaseetDebug.
Enfin,nousysommes!Dépliezànouveaulesdétailsduprojet.Vousdevezvoirlesdeuxfichiersources.
L'éditeurdecodesourceDouble-cliquezdanslenomdupremiermodulesource.Letextesourcedoits'afficherdans la fenêtre d'édition. C'est exactement ici que les yeux d'un programmeur sontposésleplussouvent,c'estlafenêtrederédactionetdecréation!
FIGURE11.16:Lepremiercodesourcedansl'éditeur.
Puisque les fichiersontdéjàété testés,nousallonsdirectementessayerdeproduirel'exécutable.
Repérezdansladeuxièmebarred'outilsenhautleboutoncontenantunpetitengrenagejauneàgauchedelaflècheverte.SalégendeestGénérer(Build).
FIGURE11.17:LeboutonGénérer(Build)delabarred'outils.
Barresd'outilsinutilesEnconfigurationd'origine,l'atelierafficheplusieursbarresd'outilsdontnousn'auronspasbesoin.Vouspouvezlesmasquercommenousl'avonsfait.Amenezlepointeurdesouris sur la poignée gauche de n'importe quelle barre (la zone grisée avec quatrepointsà laverticale)etcliquez-droit.Dé-sélectionneznotamment lesquatreoucinqbarressuivantes:
» IncrementalSearch
» NassiSchneidermannPlugin
» ThreadSearch
» DoxyBlocks
» CodeCompletion
Nous n'aurons besoin que de trois barres d'outils : Compiler, Principal etDebugger.Àdroiteduboutonàengrenage,vousdevezvoirlemotReleasedansunelistedéroulante(quinepermetdechoisirqu'entreReleaseetDebug).
LancementdelaconstructionActivez le bouton à engrenage Générer (Build) pour lancer le processus deconstructioncomplet.Toutes lesétapesprésentéesendébutdechapitres'enchaînent
sans effort. Le projet étantminuscule, vous n'aurez pas le temps d'aller prendre unverred'eauqueceseraprêt.
Observezalorslepanneauinférieurquiaaffichédesmessages.Ilmontrelejournaldegénération(Buildlog).Sivousvoyez0error(s),0warning(s),c'estparfait.
FIGURE11.18:LepanneauduJournaldegénération.
Sivousbasculezdansl'ExplorateurouleFinder,vouspouvezallervérifierquedeuxsous-dossiersontétécrééssousvotreprojet:
» undossiernommébinavecunsous-dossierReleasepourlefichier
exécutabledanssavarianteRelease;
» undossiernomméobjavecunsous-dossierReleasepourlesdeux
fichiersdecodeobjet.o.
FIGURE11.19:Lessous-dossierscréés.
Vouspouvezmaintenantadmirerlefruitdevotretravail.UtilisezleboutonExécuter(Run)avecune flècheverte.Vuquec'estunprojetde typeConsole,une fenêtredeterminalvas'ouvriràcôtédecelledel'atelier.Unepauseaétéajoutéed'officepourvouspermettredejugerdel'affichage.
Vous pouvez voir qu'unmessage en anglais confirme que le processus, donc votrefonctionmain(), a renvoyéuncode0.C'estbiencequenousavonsécrit dans ladernièrelignedelafonction:
return0;
FIGURE11.20:Leprogrammeexécutédansunefenêtredeterminal.
Appuyezsurlabarred'espacepourrefermerlafenêtre.
Vous avez terminé le parcours complet de construction d'un projet avec un atelierfenêtré.Voyonsrapidementcommentaccéderaudébogueur.
SéancededébogageLe débogueur permet d'exécuter le programme ligne par ligne en surveillantl'évolutiondesvaleursdesvariablesquevousplacezsoussurveillance.
1. OuvrezlalisteReleasedanslabarred'outilsdecompilation
pourchoisirDebug.
2. Affichezletextesourcedusecondmodule,foncModule2.cet
cliquezdanslapremièrecolonnedelalignedutestif(ligne6)
pouryposerlecurseur.Nousexécuteronsàgrandevitesse
jusqu'àcetteligne.
FIGURE11.21:PassageenmodeDébogage.
3. Justeàdroitedutrianglerougedelabarred'outilsdu
Débogueur,cliquezdansleboutonExécuterjusqu'aucurseur.
Toutl'affichagevachanger.
FIGURE11.22:L'atelierenmodeDébogage.
Unpanneauàgauche(Watches)permetdevoirlesvaleursdes
variables(ici,val).Lapiled'appelsestaumilieu(Callstack).Les
boutonsdelabarrededébogagepermettentdeprogresserde
plusieursmanières(lignesuivante,plongéedanslesous-
programme,etc.).
4. UtilisezleboutonArrêterledébogueurquandvousavez
terminévotreexploration.Vousrevenezdanslemodenormal
del'atelier.
ConclusionNous savons maintenant produire un programme exécutable. Pour augmenter notrepalette de possibilités, allons voir ce que proposent les librairies de fonctionsstandardduC.
L
Chapitre12Librairies:surlesépaulesdesgéants
DANSCECHAPITRE:
» Laroueadéjàétéinventée!
» LesfonctionsstandardduC
» Retoursurprintf()
» Fonctionsclavieretécrantexte
» Accéderàunfichierenlectureetenécriture
» Fonctionsmathématiquesetgénérationdevaleursimprévisibles
» Fonctionsdedateetd'heure
a culture humaine s'enrichit jour après jour depuis les origines de l'homme. Lesmeilleurs résultats, lesmeilleures stratégies pour répondre à un besoin viennents'ajouter au lot commun des savoirs de l'humanité dans les arts comme dans les
sciences.
Voici déjà plus d'un demi-siècle que l'on écrit des programmes.Tant de problèmessontdéjàrésolus.Demême,lapalettederéponsesauxproblèmesdesprogrammeursnecessedecroître.
Lenombredelibrairiesdisponiblesconcernedeplusenplusdedomaines:calculsscientifiques au départ, informatique de gestion, puis communications, robotique,graphismes 2D et 3D, pilotage d'engins et d'usines, santé, éducation, équipementsmilitaires,etc.
Avantd'écrirelapremièreligned'unnouveauprojet,leprogrammeurd'aujourd'huialeréflexedefairelepointsurcequiestdisponiblepourrépondreaumêmebesoinouàunbesoinapparenté.
Le programmeur cultivé sait sur quoi il peut s'appuyer pour arriver avec moinsd'efforts à son résultat. Pour l'essentiel, le capital culturel du programmeur estreprésentépardesfonctionsprédéfinies(etdesclassesenorientationobjets).
Les fonctions sont regroupées selon leur domaine d'emploi dans des librairies, degrosfichiersenréunissantdesdizainesouplus.Lerôled'unelibrairieestpurementadministratif : le fichierde librairiecontientplusieursdéfinitionsde fonctionset lefichierd'en-têteassociécontientlesprototypesdecesfonctions.
Librairieoubibliothèque?Lespremiersfrancophonesquiontcherchécommenttraduireletermeanglaislibraryont pris leur dictionnaire bilingue et en ont déduit qu'une library était unebibliothèque,unlieupartagéoùonemprunteunlivrealorsqu'unelibrairiefrançaisesedisaitbookstoreoùtoutestàvendre.
Mais cette distinction est battue en brèche avec d'une part l'arrivée du web et lemouvement Open source et d'autre part de la diffusion gratuite de livres dans ledomainepublicouenlicenceCreativeCommons.
Letermelibrairieretrouvedonctoutsonintérêt:ilestpluscourtetilressembleautermeanglaisd'origine,cequin'estpasundétailpourlimiterle«franglicisme»del'argotdesprogrammeurs.
S'il y avait une nuance àmettre en évidence, ce serait la différence entre librairiestatique et dynamique, comme indiqué dans le chapitre sur la construction/compilationdufichierexécutable.Revisitonscettedifférence.
Librairiesstatiques(.a,.lib)Sivousappelezunefonctiond'unelibrairiestatique, lecodecompilédelafonctionestextraitdufichierdelalibrairiependantl'étapedeliaisonpourêtreinjectédanslefichierexécutabledevotreprogramme.
Inconvénients:votreprogrammegrossitetdesfonctionsuniversellessontdupliquéesenmémoire,parcequeplusieursprogrammess'enservent.
Avantages : votre programme devient totalement autonome. Il contient toutes lesinstructionsqu'ilauraàexécuter.
Librairiesdynamiques(.so,.dll,.dylib)Si vous appelez une fonction d'une librairie dynamique, le code compilé de lafonction n'est pas injecté dans le fichier exécutable de votre programme. Il estimplantéenmémoiredèsqu'unpremierprogrammeappellecettefonction.
Inconvénients:lesmécanismesdemiseenrelation(d'interface)entrevosappelsetlafonctionajoutentunlégerretardd'exécution.Vousdevenezdépendantdelaprésence
surlamachinedelalibrairie,danslaversionappropriée.
Avantages : la taille de votre programme reste limitée.Tant que le prototype de lafonctionappeléenechangepas, sonauteurpeut l'amélioreretdiffuserunenouvelleversion plus efficace dont votre programme profite immédiatement.Vous limitez laconsommation de ressources (votre empreinte mémoire), ce qui participe à une«écologielogicielle».
Alors,librairieoubibliothèque?Avec une librairie statique, vous vous appropriez le code de la fonction, ce quirevientàacheterunlivre(donc,unelibrairie).
Avec une librairie dynamique, vous empruntez le code pendant quelquesmicrosecondes, le temps d'exécuter la fonction. Cela se rapproche de l'idée debibliothèque.
Mais, il existe des bibliothèques à accès payant et des librairies web du domainepublic.Lanuancen'adoncplussoneffetdeclassificationinitial.
Ceciétantdit,statiqueoudynamique,lespréparatifsrequispourutiliserunefonctiondelibrairiesontquasimentlesmêmes.
Commentprofiterd'unelibrairie?Troisétapessontrequisespourpouvoirutiliserunefonctionprédéfinie:
» Étudierl'interfacedelafonctionrecherchée.Puisquetoutesces
fonctionsstandardsontexternesàvotretextesource,unprototype
estobligatoire.L'ensembledesfichiersd'en-tête.hstandardpermet
àl'analyseurdeconnaîtrelasignaturedetoutescesfonctionsafin
devérifierquevouslesappelezcorrectement(typeetparamètres).
» Demanderl'inclusiondufichierd'en-têtecontenantleprototypede
lafonctiondésiréeparunedirective#include)endébutdefichier
source;
» Pourleslibrairiesautresquestandard,configureruneoptionde
lignedecommandeoudel'outildeproductionpourqu'iltrouvele
chemind'accèsaufichierdelalibrairie.
Lesdeuxformatsde#includeLadirectived'inclusiondoitspécifierunnomdefichier.Lasyntaxen'estpaslamêmeselonqu'ils'agissed'unfichierdelalibrairiestandardoupas.
Lorsquelenomdefichierestdélimitépardeschevrons,l'analyseurn'irachercherlefichierquedanslesdossiersdeslibrairiesstandard:
#include<stdio.h>
Enrevanche,silenomestdélimitépardesguillemetsdroits,c'estàvousdepréciseroùsetrouvelefichier,saufs'ilestdanslemêmedossierqueletextesource:
#include"maFoncNue.h"
Lesfonctionsstandard:unemalleautrésor
La librairie fondamentale du langage C réunit des centaines de fonctions surlesquellespeuvents'appuyertouteslesautreslibrairiesspécifiquesàundomaine.
Cettelibrairiestandardporteunnomvariable(libc,libgccouglibc)selonlavariantedesoutilsetlaplate-forme(Windows,MacOS,Linux,Unix).
Passer en revue le contenu de cette librairie donne une bonne idée générale descapacitésfonctionnellesauxquellesvousavezdirectementaccèssansplusd'effortquel'appelàlafonctiondésirée.
Nous avons sélectionné dans un premier tableau six groupes de fonctions quirépondentàlamajoritédesbesoins.Cetensemblereprésenteplusde130fonctions.Lesgroupessontprésentésparordred'importancedécroissante.
Tableau12.1:LessixgroupesmajeursdelalibrairieprincipaleduC.
Nom Contenu
stdio.h Groupequasimentindispensabledanstoutprogramme,neserait-ce
queparcequ'ilcontientleprototypedeprintf().Ildéfinittrois
types,quelquesmacrosetsurtoutplusde40fonctionsdédiéesaux
opérationsd'entréeetdesortieverslesfichiersoulecoupleclavier/
écran.Rienn'estprévupourlasouris,puisquenoussommesicien
modetexte.
stdlib.h Définitquatretypesdevariables,desmacrosetunetrentainede
fonctionsàusagegénéral:réservation/restitutiond'espacemémoire,
valeursaléatoires,conversionentretableauchaîneetautrestypes,
etc.
math.h Regroupeunevingtainedefonctionsdédiéesàlatrigonométrieet
auxcalculssurlesvaleursflottantes.
ctype.h Déclaretreizefonctionspourgérerdescaractèresindividuels.
string.h Déclareunevingtainedefonctionsdemanipulationdetableaux
chaînes.
time.h Réunitneuffonctionsdelectureetdeconversiondeformatpourles
datesetheuresainsiquequatretypesdedonnéesd'heure.
Lesdixautresgroupesci-dessouscontiennentdesfonctionsmoinsusitées,etcertainsfichiersd'en-têtenecontiennentmêmepasunprototypedefonction.Enrevanche,ilsdéfinissentdesmacrosetdestypesdevariablesstandard.
Tableau12.2:AperçudesgroupessecondairesdelalibrairieprincipaleduC.
Nom Contenu
complex.h Gestiondesnombrescomplexes(réel+imaginaire).
locale.h Configurationrégionale(symbolemonétaire,formatsdedate).
Définitunestructurelconvetdéclarelesdeuxfonctionssetlocale()
etlocaleconv()pourlireoumodifierlaconfigurationrégionale.
setjmp.h Interventionsurlemécanismedegestiondesappelsetretourde
fonctions.
signal.h Gestiondesignauxémispendantl'exécution(fonctionssystème).
Aucunefonctiondanslessuivantes
assert.h Définitlamacroassertpourtesterunevaleurpendantl'exécution
etréagirsielleesthorsnormes.
errno.h Gestiondelavariablesystèmeentièreerrnoquelesystème
renseigneencasdeproblème.
float.h Constantesspécifiquesàlaplate-forme(processeur16,32,64
bits).
limits.h Plagedevaleurslimitesdestypesdevariables(char,int,etc.).
stdarg.h Typedevariablepourgérerunelistedeparamètresvariable
va_list(fonctionsdéfiniesavecdespointsdesuspensionenfinde
listedeparamètres).
stddef.h Typesetmacrospourlaplupartdéfinisaussidansd'autres
fichiers.
Lafamilledesentrées/sorties(stdio.h)Le nom stdio signifie STanDard Input/Output. Ces fonctions servent à prendre lerelais de votre programmepour les opérations d'import et d'export de valeurs versl'extérieur. Par extérieur, on désigne tout ce qui est en dehors du coupleprocesseur/mémoire vive : un disque dur, une clé de stockage USB, un port decommunicationréseau,unécrand'affichageenmodetexte,unclavier.
Pour les sorties, l'écran est symbolisé par le nom stdout. Il reçoit aussi saufmention contraire les messages d'erreur qui sont envoyés vers la pseudo-sortienomméestderr.
Pourlesentrées,leclavierestsymboliséparlenomstdin.
Laplusconnueetindispensabledesfonctionsdestdioestprintf()quipermetauprogrammeurdesavoircequefaitsonprogrammeetd'enassurerlamiseaupoint.
Ilfautdistinguerlesbesoinsduconcepteurduprogrammedeceuxdesesclients(lesutilisateurs futurs). De nos jours, quasiment tous les projets sont conçus pourfonctionnerdansuneinterfacegraphique(nousverronsceladanslaprochainepartie).Lesfonctionsclavieretécrandelalibrairiestandardnesontplusutilisablescarvousn'avez plus directement accès à ces périphériques depuis votre programme. Enrevanche, le programmeur a besoin de faire afficher desmessages et de saisir desparamètrespourtestersonprojet.
Voyonslesprincipalesoptionsdeprintf()utilesauprogrammeur.
Retoursurprintf()Cette fonction estd'une richesse incroyable,mais il n'est pas rentabledepasserdutemps à maîtriser toutes les subtilités de sa syntaxe. Nous allons tester quelquesformateursetséquencesd'échappementquirépondentàpresquetouslesbesoins.
Lepremierparamètredelafonctionestunechaînelittéraletrufféedemétacaractères.Cette chaîne sert de patron d'affichage. Elle peut combiner du texte littéral, desformateurs débutant par% et des séquences d'échappement débutant par une barreobliqueinverse.
Lessixséquencesd'échappementlesplususitées
\n Sautdeligne(Newline,valeurhexa0A)
\r Retourchariot(valeurhexa0D)
\t Tabulation(valeurhexa09)
\\ Pourafficherlabarreobliqueinverse(valeurhexa5C)
\' Pourafficherl'apostrophe(hexa27)
\" Pourafficherleguillemet(hexa22)
Lesformateurs%deprintf()lesplususités
%d Considèrelavaleurnumériquecommeunentiersignéetl'afficheen
décimal.
%u Comme%d,maispourdesvaleursnonsignées.Remplacerparle
formateuropourafficherenoctaletparXpourl'hexadécimal.
%lu Lelinsérédemandedeconsidérerlavariantelong.
%llu Ledoublelldemandedeconsidérerlavariantelonglong.
%c Traduitlavaleurdel'octetenreprésentationdecaractère.
%s Mêmetraductionpouruntableauchaînequidoitêtrefournientant
quepointeur(nomdutableauseul).
%f Considèrelavaleurnumériquecommeunnombrerationnel(flottant),
donctoujourssignéetl'afficheavecsixchiffresdeprécision.
%e Comme%f,maisutiliseleformatscientifiquepourl'affichage.
%g Appliquesoit%f,soit%epouroffrirlameilleureprécision.
%p Affichelavaleurd'unevariablepointeur(uneadresseenhexa).
Passonsenrevueleseffetsdequelquescombinaisons.
LISTING12.1Textesourcelib_printf.c
//lib_printf.c
#include<stdio.h>
#include<stdlib.h>
intmain(void)
{
charicVal=117;
inti_Val=16777217;
longlongiLVal=12345678912345678;
floatf_Val=-4325.25;
doublefdVal=1.81794E-3;
charstVal[]="Jesersdephrasedetest.";
int*ptrIVal=&i_Val;
printf("\\n***Testsdeprintf()***\\n");
printf("Valeurcharavecd=%d\n",icVal);
printf("Valeurcharavecc=%c\n",icVal);
printf("\n***Testsdecadragesurint***\n");
printf("Valeurintavecd=|%d|||\n",i_Val);
printf("Valeurintavec-12d=|%-12d|||\n",i_Val);
printf("Avec12detsigne+=|%+12d|||\n",i_Val);
printf("Lignedereperage=|****99999999|||\n");
printf("16300enhexadecimal=|%X|\n",16300);
printf("Valeurlonglong=|%llu|||\n",iLVal);
printf("\n***Testsdecadragesurfloat***\n");
printf("Valeurfloatavecf=|%f|||\n",f_Val);
printf("Valeurintavec5.1f=|%5.1f|||\n",
f_Val);
printf("Valeurintavec3.5f=|%3.5f|||\n",
f_Val);
printf("\nValeurdoubleavece=|%e|||\n",
fdVal);
printf("Valeurdoubleavecf=|%f|||\n",fdVal);
printf("Valeurdoubleavec5.9f=|%5.1f|||\n",
fdVal);
printf("\n***Testsdecadragesurtableaux
chaines\n");
printf("Valeurchaineavecs=|%s|||\n",stVal);
printf("Valeurchaineavec30s=|%30s|||\n",
stVal);
printf("Valeurchaineavec-10s=|%-10s|||\n",
stVal);
printf("\n***Onfinitavecunpointeur***\n");
printf("Valeurdepointeuravecp=|%p|\n",
ptrIVal);
printf("Contenudecetteadresse=|%d|\n",
*ptrIVal);
return0;
}
Les barres verticales n'ont aucun effet spécial. Elles augmentent la lisibilité desaffichages.Voicilesrésultatsàl'écran,commentésgroupepargroupe.
***Testsdeprintf()***
Valeurcharavecd=117
Valeurcharavecc=u
***Testsdecadragesurint***
Valeurintavecd=|16777217|||
Valeurintavec-12d=|16777217|||
Avec12detsigne+=|+16777217|||
Lignedereperage=|****99999999|||
16300enhexadecimal=|3FAC|
Valeurlonglong=|12345678912345678|||
***Testsdecadragesurfloat***
Valeurfloatavecf=|-4325.250000|||
Valeurintavec5.1f=|-4325.2|||
Valeurintavec3.5f=|-4325.25000|||
Valeurdoubleavece=|1.817940e-003|||
Valeurdoubleavecf=|0.001818|||
Valeurdoubleavec5.9f=|0.0|||
***Testsdecadragesurtableauxchaines***
Valeurchaineavecs=|Jesersdephrasede
test.|||
Valeurchaineavec30s=|Jesersdephrasede
test.|||
Valeurchaineavec-10s=|Jesersdephrasede
test.|||
***Onfinitavecunpointeur***
Valeurdepointeuravecp=|0028ff1c|
Contenudecetteadresse=|16777217|
Autresfonctionsdedialoguedestdio.hCettefamilleestl'unedesplusfondamentales.Faisonsunrapidetourdupropriétairedetouteslesfonctionscollèguesdeprintf()dansstdio.h.
LelangageCétantintimementliéausystèmeUnix,ilenhériteleconceptdefluxdedonnées(stream).Les fichiers sont considérés, tout comme le clavier et l'écran, entantquesourceset/oudestinationsd'unflux.
Gestiondesconteneurs(ouvrir,fermer,naviguer)
Ouvriretfermer
FILE*fopen(constchar*nomfic,constchar*mode)
Ouverturedufichiernomficdanslemodespécifié.
FILE*freopen(constchar*nomfic,constchar*mode,
FILE*flux)
Associationd'unautrenomàunfluxouvertetlibérationdel'anciennom.
intfflush(FILE*flux)
Forçaged'écrituredesdonnéesenattenteversleflux.
intfclose(FILE*flux)
Fermetureduflux(forcelesécrituresenattente).
intfeof(FILE*flux)
Testdel'étatdel'indicateurdefindefichierEOF.
FILE*tmpfile(void)
Constructiond'unfichiertemporaireenmoded'ajoutbinaire(wb+).
char*tmpnam(char*str)
Générationetrenvoid'unnomdefichiergarantiunique.
Positionnementdirectdansleflux
intfgetpos(FILE*flux,fpos_t*pos)
Lectureducurseurdepositiondanslefluxetcopiedanspos.
intfsetpos(FILE*flux,constfpos_t*pos)
Ecritureducurseurdepositiondansleflux.Leparamètreposestuncurseurtelquerenvoyéparfgetpos().
intfseek(FILE*flux,longintoffset,intwhence)
Changementdepositionrelativeducurseurselonoffsetquiestunnombred'octetsdepuislapositionactuelle.
longintftell(FILE*flux)
Lecturedelapositioncourantedansleflux.
voidrewind(FILE*flux)
Réarmementducurseurdepositionautoutdébutduflux.
Fonctionsd'écriture
Fonctiongénérique
size_tfwrite(constvoid*ptr,size_tsize,size_tn,
FILE*flux)
Ecrituredesdonnéesdutableaupointéparptrdansleflux.
Radicalprint(imprimer)
intfprintf(FILE*flux,constchar*format,...)
Ecriturededonnéesmisesenformeversleflux.
intprintf(constchar*format,...)
Ecriturededonnéesmisesenformeversstdout.
intsprintf(char*str,constchar*format,...)
Ecriturededonnéesmisesenformeversuntableauenmémoire.
vfprintf(),vprintf(),vsprintf()
Troisvariantesaveclisted'argumentsvariables.
Radicalput(poser)
intfputs(constchar*str,FILE*flux)
Ecritured'untableauchaîneversleflux(sanslezéroterminal).
intputs(constchar*str)
Ecritured'untableauchaîneversstdout(sanslezéroterminal,maisavecunsautdeligne).
intfputc(intchar,FILE*flux)
Ecritured'uncaractèreverslefluxetavancementducurseurdepositiondansleflux.
putc(),putchar()
Deuxvariantesdéconseilléesdefputc().
Fonctionsdelecture
Fonctiongénérique
size_tfread(void*ptr,size_tsize,size_tnmemb,FILE
*flux)
Lecturedepuisunflux/fichieretcopiedansletableaupointéparptr.
Radicalscan(lire)
intfscanf(FILE*flux,constchar*format,...)
Lectureavecformatdepuisunflux/fichier.
intscanf(constchar*format,...)
Lectureavecformatdepuisstdin.
intsscanf(constchar*str,constchar*format,...)
Lectureavecformatdepuisuntableauchaîneenmémoire.
Radicalget(prendre)
char*fgets(char*str,intn,FILE*flux)
Lectured'unelignedepuisunflux/fichieretstockagedansletableauchaînepointéparstr.S'arrêteaprèsavoirlun-1caractèresouavoirdétectéunsautdeligneoulafindefichier(EOF).
char*gets(char*str)
Commefgets()maislimitéeàl'entréestandardstdinquiestleclavier.DétectelatoucheEntrée.
intfgetc(FILE*flux)
Lecture du prochain caractère depuis un flux/fichier et avancement du curseur depositiondansleflux.
intgetc(FILE*flux)
Lectureduprochaincaractèredepuisstdinetavancementducurseurdepositiondansletamponclavier.
intungetc(intchar,FILE*flux)
Renvoidechardanslefluxpourqu'ildevienneleprochainlu.
intgetchar(void)
Lectured'uncaractèredepuisstdin.
Gestiondeserreursetdivers
intferror(FILE*flux)
Testdel'indicateurd'erreurdeflux.
voidclearerr(FILE*flux)
Désactivationdesindicateursdefindefichieretd'erreurduflux.
voidperror(constchar*str)
Affichaged'unmessaged'erreurversstderràpartirdestrpuisunsignedeux-pointsetunespace.
intremove(constchar*nomfic)
Effacementdunomdefichierquidevientinaccessible.
intrename(constchar*ancnomfic,constchar
*nouvnomfic)
Changementdenomd'unfichier.
voidsetbuf(FILE*flux,char*buffer)
Configurationdel'utilisationd'untamponmémoirepourunflux.
intsetvbuf(FILE*flux,char*buffer,intmode,size_t
size)
Similaireàsetbuf().
Illustronscesfonctionspartroisexemples:
» Lepremiermontrecommentrécupérerdesvaleurssaisiesau
clavier.
» Ledeuxièmemontrecommentécrireetreliredesvaleursdansun
fichiertexte.
» Ledernierfaitdemêmemaisdansleformatdefichierbinaire.
SaisiededonnéesauclavierLesfonctionsdesaisieenmodetexteduCsontpeurobustes.Laplupartnesaventpaséviter un débordement par saisie trop longue, sauf à ajouter des instructions de
contrôle.Ellessontdoncsurtoutdestinéesàl'usagedesprogrammeurspourapprendreetpourprogresserdansleurstravaux.
Dans ce bref exemple, nous utilisons une seule fonctionde lecturefgets(). Ellesait lire tout texte saisi. Pour les valeurs numériques, nous profitons de plusieursfonctions de la famille stdlib qui assurent les conversions depuis le type tableauchaîneversunentierparatoi()ouunflottantparatof().
LISTING12.2Textesourcelib_fgets.c
//lib_fgets.c
#include<stdio.h>
#include<stdlib.h>
#defineMAXCAR10
intmain(void)
{
intiVal;
floatfVal1,fVal2;
charstVal[MAXCAR+1];
printf("\n***Lecturesclavierfgets()***\n");
printf("\nSaisirdutexte(10signes)etvalider:
");
if(fgets(stVal,sizeof(stVal),stdin)!=NULL)
printf("Textesaisitelquel:%s\n",stVal);
for(iVal=0;iVal<MAXCAR+1;iVal++)
printf("%d\t",stVal[iVal]);
printf("\n");
for(iVal=0;iVal<MAXCAR+1;iVal++)
printf("%c\t",stVal[iVal]);
//Iciviendradequoividerlestockdestdin
printf("\nSaisirunevaleurintegeretvalider:");
fgets(stVal,sizeof(stVal),stdin);
if((iVal=atoi(stVal))==0)printf("Nulle?
\n");
printf("Valeursaisie:%d\n",iVal);
printf("\nSaisirunevaleurfloatetvalider:");
fgets(stVal,sizeof(stVal),stdin);
fVal1=atof(stVal);
printf("Valeursaisie:%f\n",fVal1);
printf("\nSaisirunesecondevaleurfloatet
valider:");
fgets(stVal,sizeof(stVal),stdin);
fVal2=atof(stVal);
printf("Valeursaisie:%f\n",fVal2);
fVal1+=fVal2;
printf("\nSommedesdeuxfloat:%f\n",fVal1);
return0;
}
Nous choisissonsd'utiliser à quatre reprises la fonction standardde lecture de fluxnomméefgets().Lenomestcomposédufdefichier,duverbeget(prendre)etdelalettrespourstring(tableauchaîne).
Nousavonspréférélafonctionfgets()parcequ'elleestpolyvalente:ellepermetdetravailleravectouslesflux,principalementlesfichierssurdisque,maisaussi lefluxd'entréestandardsymbolisépar lemotcléstdin.Sauf instructionderedirection(onpeutréorienterstdin),ils'agitduclavierdelamachinesurlaquellefonctionneleprogramme. Elle a aussi l'avantage d'obliger à préciser le nombre de caractères àprendreencompte,cequiévite lessoucisdedébordementdontsouffresacollèguegets()etlacomplexitédesonautrecollèguescanf().
Syntaxedefgets()Voyons la syntaxe générique defgets(). Elle attend trois paramètres d'entrée etrenvoieunevaleurdetypepointeursurtableau:
fgets(tabchaine,nombrecar,stdin);
Lafonctionrenvoieletableautabchainerempli(l'adressedupremierélément,enfait)oulavaleurNULLencasdesouci.Danslepremierappel,nousfaisonsletest,mais pas dans les suivants parce qu'a priori l'utilisateur va saisir ce qu'on luidemandedanscebrefexemple.
LetextequenoussommesinvitésàsaisirserastockédansletableauchaînestValque nous avons limité à dix caractères (voir la directive qui définitMAXCAR audébut). Nous exprimons cette longueur maximale dans l'appel au moyen desizeof(stVal).Letableauoccupeonzeoctetscarnousavonsprissoindegarderunepetiteplacepourlezéroterminal.
Lesous-systèmedelamachinequigèreladétectiondestouchesfrappéesauclavierpossèdesonpropreespacemémoire(untampon,buffer).Lorsquevoussaisissezplusdedixcaractères,seulslesdixpremierssontcaptésparlafonctionfgets().C'estbienlebutdelaposed'unelimite.Maiscen'estpassisimple.
S'il y a eu saisie de plus de caractères, ceux en trop vont alimenter sans que vousl'ayezvoululesprochainsappelsàfgets().Sicesuperflunereprésentepasdesnombres, les valeurs numériques vont être forcées à zéro par les fonctions deconversion atoi() et atof() qui ne savent convertir que les caractèresreprésentantdeschiffresde0à9.
LesuperflupeutgênerLescaractèressuivantsenattentedansletamponclaviersontdoncdesparasites.Pouréviter ce genre de désagrément, il suffit de forcer le vidage du tampon clavier enlisantcequiytraînepourlejeter.
Dansletextesourceprécédent,nouspouvonsremplacerlalignedecommentaires//Ici viendra… par le bloc suivant pour purger le tampon mémoire d'entréeclavier.
intcharentrop;
while((charentrop=getchar())!='\n'&&
charentrop!=EOF)
;
Nousdéclaronsunevariablede travail puisnous cherchons la conjonctiondedeuxcasparticuliers:
(charentrop=getchar())!='\n'
Danscettepremièresous-expression,nousrécupéronsparappelàgetchar() leprochaincaractèreenattentedansstdin(aprèsceuxrécupérésparfgets())etnousleconfrontonsaucodedusautdeligne(touchedevalidationEntrée).
charentrop!=EOF
Laseconde sous-expressionconfronte le caractère extrait aucodede finde fichier.Pourstdin,celacorrespondàlafindustockdecaractères.Vouspourrezréutiliserceblocdetesttelquelpourvoslecturesdefichierstexte.
Si et seulement si les deux conditions sont réunies (opérateur&&), nous exécutonsl'unique instruction de ce bloc conditionnel : un point-virgule isolé ! Oui, nous nefaisons rien. Enfin, presque rien. Chaque appel à getchar() consomme uncaractèreenattente,cequinouspermetdeviderletamponclavierpourrepartirsurdesbasessainespourlaprochainesaisie.
Dansl'exemple,nousneprenonspascetteprécautionpourlasaisiedestroisvaleursnumériques,maislemêmeraisonnements'applique.
Le coupleprintf()/fgets() permet de gérer les échanges de données avecl'utilisateur. Vous savez que toutes les données de vos programmes se volatilisentlorsqueleprogrammesetermine.
Voyons donc comment lire et écrire des données dans un fichier pour les rendrepermanentes et pouvoir les réinstaurer dans l'espacemémoire du programme à sonprochaindémarrage.
Lecture/écrituredansunfichiertexteLes fichiers isolés sontdevenus raresdenos jours.Lemoindresitewebstocke lesdonnéesdansunebasededonnéesrelationnellecontrôléeavecunlangagespécialisé,quiestsouventlelangageSQL.Ilrestenéanmoinsutiledesavoirstockeretreliredesdonnéessimplespourenassurerlaconservation.
LelangageCproposedeuxformatsdestockage:texteoubinaire.
Etapesd'exploitationd'unfichiertexteExploiterunfichiersupposetroisétapes:
1. Ouverturedufichieraveclafonctionfopen()(sansoublierles
testsappropriéspourgérerlessituationsanormalestelles
qu'unfichierintrouvable).
2. Utilisationdesfonctionsdelectureetd'écriturefgets(),
fwrite(),etc.(et,enoption,denavigationauseindufichier
grâceàuncurseurdeposition).
3. Fermeturedufichieraveclafonctionfclose().
Commençonsparlasyntaxeformelle(leprototype,enfait)delafonctionfopen():
FILE*fopen(constchar*nomfic,constchar*mode)
Vousdevezêtreétonné.Lalignecommenceparuntermeencorejamaisrencontré,làoù vous avezmaintenant l'habitude de voir un nom de type (int,float, void,etc.).
FILE est un nouveau type. c'est une structure (chapitre suivant) qui regroupeplusieursvariablesdes typescharetintpourgérer l'interface avec le systèmed'exploitation au sujet d'un fichier. C'est un mot réservé. La fonction d'ouverturerenvoieunetellestructurerenseignéeaveclesparamètresappropriéspourdialogueraveclesystème.
Lafonctionfopen()attenddeuxparamètres:lenomdufichier(untableauchaîne)et un minuscule tableau chaîne pour sélectionner le mode d'ouverture. Plusieursquestionssontàrépondreavantdetenterd'ouvrirunfichier:
» S'agit-ildecréerunfichiern'existantpasencoreoudemodifierun
fichier?
» Siunfichierportantlenomdemandéexiste,voulez-vouseffacer
soncontenuactuelpourrepartiràzéroouajouteràl'existant?
» Voulez-vouslirelecontenuouystockerducontenuouencoreles
deux?
» Voulez-vousystockerdutexte(ycomprisdesvaleursnumériques
convertiesenchiffreslisibles)oubienuniquementdesdonnées
numériquescompactes,«tellesqueleprogrammelesconnaît»?
Enrépondantàcesquestions,vousalleznaturellementtrouverquelmoded'ouverturechoisir.
Indicateursdemoded'ouverture
Touslesindicateursquisuiventconcernentl'ouvertureenformattexte.Pourtravailleren formatbinaire (formatbrut),vousajoutez la lettrebàvotremode (commedansr+b).
Tableau12.3:Modesd'ouvertured'unfichierauformattexte.
Mode Description
"r" (read)Ouvertureenlectured'unfichierquidoitexister.
"w" (write)Créationd'unfichierparsuppressionducontenuantérieur
éventuel.Méfiez-vous.
"a" (append):Ouverturesanssuppressionducontenuantérieuréventuel.
Lesdonnéesserontajoutéesàlafindel'existant.Silefichiern'existe
pasàl'endroitdemandé,ilestcréé.
"r+" (read/update):Ouvertureenlectureetenécritured'unfichierquidoit
pré-exister.
"a+" append/update:Commelemode"a"enyajoutantlalectureetl'accès
auxfonctionsdenavigationdanslefichieraveclecurseur(fseek(),
fsetpos(),rewind()).
Appliquons ces connaissances à un exemple complet. Le bon fonctionnement duprogrammesupposequedanslemêmedossieriltrouveunfichierportantexactementle nom fic_ronsard.txt. S'il n'est pas trouvé, unmessage apparaît et le programmeabandonne.
LISTING12.3Textesourcefic_ronsard.c
//fic_ronsard.c
#include<stdio.h>
#include<stdlib.h>
#defineNBRCOL50
intmain()
{
shortlignum=0;
FILE*fh;//1
chartabstr[80+1];
fh=fopen("fic_ronsard.txt","r+");//2
if(fh==NULL)
{
puts("Ouvertureimpossible!");
exit(1);//3
}
while(fgets(tabstr,NBRCOL,fh)!=NULL){//4
printf("%3d:%s\n",lignum,tabstr);
lignum++;
}
printf("\n\nOserons-nousajouteruneligne:");
fgets(tabstr,80,stdin);//5
fputs(tabstr,fh);
fclose(fh);
return(0);
}
Cinqpassagessontremarquables.Voirlesrenvois//:
1. Ils'agitd'unedéclarationdetypededonnée.LetypeestFILE
(voirplushaut)etlavariableestunpointeur,caractériséepar
l'astérisque.Onappellecegenred'élémentunidentificateur,
unepoignéeouunhandle(d'oùlehpourfilehandle).Vouslerecevezdusystème,etvousvousenservezsanslemodifier.En
direplusnousemmèneraitloinsansvraieraison.
2. L'appelàfopen()renvoieunidentificateurquenousstockons
dansl'élémentfh.Deuxparamètres:lenomdufichieràtraiter
etlemoded'ouverture.Lemoder+ouvredanslemode
bidirectionnel.
3. Lalignesuivantepermetd'arrêterlesfraissilefichierest
introuvable.Nousprofitonsdelafonctionsystèmeexit()
poursortirsansménagementduprogramme.C'estbrutal,mais
efficace.
4. L'opérationdelectureparfgets()renvoieuntableau(un
pointeurenfait),maiscommenousindiquonsletableau
récepteurtabstrenpremierparamètre,nousn'avonspas
besoindecapterleretourdefonction.Enrevanche,encasde
souci,lafonctionrenvoielavaleurspécialeNULL.C'estceque
noustestonsdansunebouclequiincarnelepointcentraldu
programme.Tantquelalecturen'échouepas,nousaffichonsle
numérodelignepuislisonsdansfhuneligned'aumaximum
NBRCOLcaractèresetincrémentonslenumérodeligne.Ilpeut
s'enpasserdeschosesenuneseulelignedeC!
5. Nousutilisonsalorsfgets()nonaveclefichier,maisavecle
clavier(stdin)pourproposerlasaisied'auplus80caractères
quenousajoutonsparfputs()àlafindufichier.Nous
terminonsenfanfareparunefermeturedufichieravec
fclose().
Nerésistonspasauplaisirdereproduireledébutdurésultataffichépournotrefichierdetest,unextraitdutome7desœuvresdePierreRonsard.
0:AUXBONSETFIDELESMEDECINSPREDICANS,SURLAPR
1:ISEDESTROISPILLULESQU'ILSM'ONTENVOYÉES.
2:Mesbonsetfidelesmedecinspredicans,toutains
3:yquedegayetédecœuretsansfroncerlesourcy
4:j'aygobbéetavalélestroispillulesquedevo
5:stregracem'avezordonnées;lesquellestoutesfoi
6:sn'ontfaictenmoncerveaul'entiereoperation
7:quedesiriez,commevouspourrezcognoistreparl
8:etc.jusqu'enligne25
Sionchargelefichiertextedansunéditeuraprèsavoirquittéleprogramme,onpeutvoircequiaétésaisiencomplémentdelaproseronsardienne.Voicisonaspectdansunéditeurhexadécimal(Frhed).
Un exercice captivant consisterait à gérer les ruptures de lignes en cherchant ledernierespaceentredeuxmotsavantlamargedroiteetenrepoussanttoutlederniermotincompletsurlalignesuivante.
Latechniquenechangepaspourleformatbinaire,saufquelefichierdevientillisiblepourunhumain.Lesvaleursnumériquesstockéeslesontdirectement.
FIGURE12.1:Contenud'unfichiertexte.
Lecture/écrituredansunfichierbinaireLe formatbinaire convient au stockagededonnéesnumériquesqui seprésententdefaçonstructurée,commeparexemple:
» Uneréférenced'articlesousformed'unentiersur5chiffres.
» Unprixd'articlesousformed'unevaleurfloat.
Voiciunexempledanslequelnousdéfinissonscinqarticlesdansdeuxtableaux.
LISTING12.4Textesourcefic_stock.c
//fic_stock.c
#include<stdio.h>
#include<stdlib.h>
char*debut="AAAA";
intndx,numelem[5]={0};
intArticle[5]={2340,87520,124,12520,1987};
floatPrix[5]={3.40,75.20,12.4,25.20,9.87};
voidVisualiser(intenreg);
intmain()
{
intqte=5;
FILE*fh;
charts[10+1];
charnomfic[]="fic_stock.bin";
for(ndx=0;ndx<qte;ndx++){
numelem[ndx]=(short)ndx;
Visualiser(ndx);
}
fh=fopen(nomfic,"wb+");
if(!fh){
puts("Ouvertureimpossible!");
return(1);
}
for(ndx=0;ndx<qte;ndx++){
numelem[ndx]=ndx;
fwrite(debut,4,1,fh);
fwrite(&numelem[ndx],sizeof(int),1,fh);
fwrite(&Article[ndx],sizeof(int),1,fh);
fwrite(&Prix[ndx],sizeof(float),1,fh);
}
printf("\n\nSaisir0,16,32ou48:\n");
intdecala;
decala=atoi(fgets(ts,10,stdin));
fseek(fh,decala,SEEK_SET);
for(ndx=0;ndx<2;ndx++){
numelem[ndx]=ndx;
fread(debut,4,1,fh);
fread(&numelem[ndx],sizeof(int),1,fh);
fread(&Article[ndx],sizeof(int),1,fh);
fread(&Prix[ndx],sizeof(float),1,fh);
Visualiser(ndx);
}
fclose(fh);
return(0);
}
voidVisualiser(intenreg){
printf("\n\nDebut=%s",debut);
printf("\n\nNumelem=%d",numelem[enreg]);
printf("\nReference:%5d",Article[enreg]);
printf("\nPrix:%4.2f",Prix[enreg]);
}
Nousutilisonsdenouvellesfonctionspourlireetécrire.fwrite()etfread()ont les mêmes trois paramètres : l'adresse d'un élément de tableau, la taille del'élémentenoctetsetlelienfichierdéjàconnu.
Pourl'ouverture,nousspécifionsuneouverturepourécritureetajoutenformatbinairepar"wb+".
Lagrandenouveautéest l'appelàfseek()qui permet dedéplacer le curseur depositionnementparrapportàtroislieuxparticuliers.
fseek(fh,decala,SEEK_SET);
Lespositionssontexpriméesenoctets:
SEEK_SETsymboliseledébutdufichier(position0).
SEEK_ENDsymboliselafindufichier(positionjusteavanterreurEOF).
SEEK_CURsymboliselapositionactuelleaprèsladernièrelectureouécriture.
FIGURE12.2:Contenud'unfichierbinaire.
Ledeuxièmeparamètre permet d'ajouter un décalage en octets par rapport au pointd'ancrage choisi. Dans l'exemple, nous avons choisi de nous repositionner tout audébut.Dufaitquechaqueenregistrement(lestroisvaleursd'unarticle)occupeseizeoctets(lachaînesur4octetspuis3fois4),nouspouvonspasseraudébutdechaquearticle en indiquantunmultiplede16.Lesdécalagesnégatifs sontpossibles : vousremplacez SEEK_SET par SEEK_END et recompilez. Pour le décalage, vousindiquez-16,-32,etc.
Biensûr,denombreusesaméliorationssontpossibles,maisellesrendraientl'exemplemoinsinstructif.Lachaînedebutparexemplen'aétéajoutéequepourfaciliter lerepéragedesdébutsd'enregistrementsdanslaFigure12.2.
Danslafigure,vouspouvezvoirledébutdechacundecinqenregistrements.
Lesfonctionsélémentairesdestdlib.hCommesonnomlesuggère,lafamilledefonctionsstdlibrépondàdiversbesoinsélémentaires.Nousenavonsdéjàexploitécertainesdans lesexemplesprécédents :atoi(),atof()etexit().Voyonscequinousestproposé.
Conversionsentrechaîneetnumérique
Les trois fonctionsdont lenomcommenceparstrsont préférables à leurs sœurscommençantparunacarcesdernièresnedétectentpasleserreurséventuelles.
Nom Typedurésultatàpartird'untableauchaîne
atof() double
atoi() int
atol() longint
strtod() double
strtol() longint
strtoul() unsignedlongint
Avantd'utilisern'importequellefonction,renseignez-voussurlasyntaxedétailléeetletypedelavaleurrenvoyée.Ilsuffitdesaisirlenomdelafonctionetl'expression«langageC»dansunmoteurderecherche.
Réservationetlibérationdemémoiredynamique
void*calloc(size_tnitems,size_tsize)
Réserveunespacemémoireetrenvoieunpointeursurcebloc.
void*malloc(size_tsize)
Variantesimplifiéedecalloc().
void*realloc(void*ptr,size_tsize)
Tentedemodifierlatailled'unblocmémoireréservé.
voidfree(void*ptr)
Libèreunblocréservé.
Accèsausystèmed'exploitation
voidabort(void)
Provoquel'arrêtduprogrammeparabandon.
intatexit(void(*fonction)(void))
Désigneunefonctionquiseraappeléeenfind'exécutionnormaleduprogramme.
voidexit(intstatus)
Provoquel'arrêtnormalmaisimmédiatduprogramme.
char*getenv(constchar*nom)
Cherche un tableau chaîne dans l'environnement d'exécution et renvoie la valeurassociée.
intsystem(constchar*string)
Transfèrelalignedecommandeenparamètreausystèmepourqu'iltentedel'exécuter.
Arithmétique
intabs(intx)
Valeurabsoluedexentier.
longintlabs(longintx)
Valeurabsoluedexentierlong.
div_tdiv(intnumer,intdenom)
Divisionentreentiers.
ldiv_tldiv(longintnumer,longintdenom)
Divisionentreentierslongs.
Générationpseudo-aléatoire
intrand(void)
Renvoieunevaleurimprévisibleentre0etRAND_MAX.
voidsrand(unsignedintsemence)
Réarmelegénérateuraléatoirederand()enyinjectantunenouvelle«semence».
Les cinq fonctions de gestion des chaînes multi-octets ne concernent pas lesdébutants : mblen(), mbstowcs(), wcstombs(), mbtowc() etwctomb().Lalibrairiecontientenoutreunefonctionderecherchebinairenomméebsearch()etunefonctiondetrinomméeqsort().
Ungénérateurdevaleurpseudo-aléatoireUn groupe de fonctions très utile dans stdlib concerne la génération d'une valeurnumériqueassezimprévisiblepourlaissercroirequ'elleestlefruitduhasard.
LISTING12.5Textesourcelib_rand.c
//lib_rand.c
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
intmain()
{
inti,j,alea;
time_tt;
/*Semelagrainededepartdugenerateur*/
srand((unsigned)time(&t));
printf("Produit50valeursentre0et50:\n\n");
for(i=0;i<10;i++){
for(j=0;j<5;j++){
alea=(rand()%50);
printf("%2d\t",alea);
}
printf("\n");
}
return(0);
}
Nousnousservonsd'unevariabled'untypeévolué(time_t)quiestdécritplusloinaveclafamilledesfonctionstemporelles.
Lesfonctionsmathématiques(math.h)Toutescesfonctionstravaillentavecenparamètreuneoudeuxvaleursdetypedouble.
Trigonométrie:
acos(),asin(),atan(),atan2(),cos(),cosh(),sin(),
sinh(),tanh().
Puissance,logarithme,racinecarrée…:
exp(),frexp(),ldexp(),log(),log10(),modf(),pow(),
sqrt(),fabs(),
ceil(),floor(),fmod().
ExempledefonctionsmathématiquesCet exemple illustre une sélection de fonctions de cette famille.Observez bien lesvariationsparfoisétonnantesdesrésultatsparrapportàvosattentes.
LISTING12.6Textesourcelibmath.c
//lib_math.c
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
intmain(void)
{
charc_valnum=-117;
shorts_valnum=16217;
inti_valnum=16777217;
doubled_valnum=-1.25125E-4;
printf("***Testdesfonctionsmath***\n");
i_valnum=c_valnum*s_valnum;
printf("Valeurabsoluede%d=%d\n",c_valnum,
abs(c_valnum));
printf("abs()de%d=%d\n",i_valnum,
abs(i_valnum));
printf("abs()de%f=%f\n",d_valnum,
abs(d_valnum));
printf("fabs()de%f=%f\n",d_valnum,
fabs(d_valnum));
doubledBase=16.0001;
doubledExpo=5.0,dRes;
//Fonctionpuissance:pow()
dRes=pow(dBase,dExpo);
printf("\n%fpuissance%f=%f\n",dBase,dExpo,
dRes);
//Fonctionracine2:sqrt()
dBase=4.0123;
dExpo=2.01;
dRes=pow(dBase,dExpo);
printf("\n%fpuissance%f=%f",dBase,dExpo,
dRes);
dBase=sqrt(dRes);
printf("\nMaisracinecarreede%f=%f\n",dRes,
dBase);
dRes=1.0/257.0;
printf("\nVoici1/257:%f",dRes);
printf("\nRemultipl.par257:perteenlignecar%f
\n",dRes*255);
//Fonctionmodf()
doublex,fractpart,intpart;
x=8.123456;
fractpart=modf(x,&intpart);
printf("Partieentiere=%f\n",intpart);
printf("Partiefractionnaire=%f\n",fractpart);
return0;
}
Lesfonctionstemporelles(time.h)Lafamilletimedéfinitdestypesdédiésdontunestructurequiaccueillelesdonnéesmembresd'unedateetheurecomplète.
Typesprédéfinisclock_t:Typepouraccueillirl'heureprocesseur.
time_t:Typepouraccueillirl'heurecalendaire.
structtm:Structureréunissantlespartiesd'unevaleurdedateetheure.
structtm{
inttm_sec;/*secondes,de0à59
*/
inttm_min;/*minutes,de0à59
*/
inttm_hour;/*heures,de0à23
*/
inttm_mday;/*numérodujour,de1à31
*/
inttm_mon;/*mois,de0à11
*/
inttm_year;/*Annéesdepuis1900
*/
inttm_wday;/*Jourdesemaine,de0à6
*/
inttm_yday;/*Jourdansl'année,de0à365
*/
inttm_isdst;/*joursété/hiver
*/
};
Fonctionsstandard
char*asctime(conststructtm*timeptr)
Renvoieunpointeur surchaînecontenant le jouret l'heure trouvésdans la structuretimeptr.
clock_tclock(void)
Renvoie l'heure horloge du processeur depuis un début conventionnel qui estnormalementledébutd'exécutionduprogramme.
char*ctime(consttime_t*timer)
Renvoieunechaînecontenantl'heurelocaled'aprèslecontenudetimer.
doubledifftime(time_ttime1,time_ttime2)
Renvoieladifférenceensecondesentretime1ettime2.
structtm*gmtime(consttime_t*timer)
Répartit lavaleurcompositetimerdans lastructuretmen l'exprimant en tempsUTCouGMT.
structtm*localtime(consttime_t*timer)
Répartit lavaleurcompositetimerdans lastructuretmen l'exprimant en tempslocal(fuseauhoraire).
time_tmktime(structtm*timeptr)
Convertitlastructuretimeptrenvaleurtime_tentempslocal.
size_tstrftime(char*str,size_tmaxsize,constchar
*format,conststruct
tm*timeptr)
Met en forme le contenude la structuretimeptrselon les règles dans format etstockelerésultatdansstr.
time_ttime(time_t*timer)
Extraitl'heurecalendaireetlarenvoieauformattime_t.
ObtenirladatedujourLe court exemple qui suit permet d'interroger le système pour afficher la date etl'heurequ'ilpenseêtre.
LISTING12.7Textesourcedatejour.c
#include<stdio.h>
#include<time.h>
intmain()
{
time_tt;
structtm*ti;
constchar*njo[]={"dim","lun","mar","mer",
"jeu","ven","sam"};
constchar*nmo[]={"jan","fev","mar","avr",
"mai","jun","jul","aou",
"sep","oct","nov","dec"};
t=time(NULL);
ti=localtime(&t);
printf("\n****************************");
printf("\nNoussommesle%d%s%d,un%s\n",
ti->tm_mday,
nmo[ti->tm_mon],
ti->tm_year+1900,
njo[ti->tm_wday]);
printf("Ilest%02d:%02d:%02d\n",
ti->tm_hour,
ti->tm_min,
ti->tm_sec);
printf("****************************\n");
return0;
}
Danscetexemple,remarquezl'appelsuivantquipeupleunestructuretemporelleavecl'heurelocale:
ti=localtime(&t);
Touteslesexpressionsdustyleti->tm_mdayutilisentl'opérateur->d'accèsàunmembredestructure,cequenousverronsendétaildèsledébutduprochainchapitre.
LeslibrairiesspécifiquesUne librairie de fonctions peut faire économiser énormément de temps ou mêmerendrepossibleunprojet.Vouspouvezcréervotrelibrairie,maisengénéralcelan'envaut la peine que si vous savez que d'autres auront besoin des services qu'ellecontient.
Une librairie représente des centaines ou des milliers d'heures de conception, derédactionetdemiseaupoint.C'estpourquoicertaineslibrairiessontcommercialiséesalorsqued'autressontgratuites.
Par ailleurs, une librairie se présente au format compilé, directement utilisable parvosprogrammes,maisvousn'enconnaissezpaslesdétails.
Cependant, certaines librairies, et toutes les librairies diffusées avec une licenceGPL,sontopensource : le textesourcede toutes les fonctionsestdisponibleaussi,pourétudeoupouramélioration.
Unelibrairieestsouventprévuepourêtreexploitéedansplusieurslangages,maispastoutes. Pour devenir utilisable dans un système d'exploitation (Linux, Windows,Linux),elledoitêtreconstruiteenconformitéavecuneinterfacebinairenomméeABI(ApplicationBinaryInterface).
QuelqueslibrairiesdegestiondedonnéesDèsquevotreprojetdoittraiterdegrandsvolumesdedonnées,iln'estpluspratiquedetravailleravecdesfichierssimples.Ilvousfautunevéritablearchitecturecapablede gérer plusieurs fichiers liés sous forme de tables avec des relations entre leschampsdestables.LemodèleleplusrépanduactuellementestlabaseSQL.
» MySQL:Moteurdegestiondebasesdedonnéesrelationnelles
(SGBD)fondésurlelangageSQL.
» SQLite:Versionlégèreduprécédent.
» Cassandra:MoteurdebasesdedonnéesnonSQL(interfaceavec
Java,PythonetNode.js,maispasavecleC).
QuelqueslibrairiesgraphiquesLescalculsd'objets endeuxouen troisdimensionspour affichage représententuneimportante catégoriedebesoinsqueviennent comblerdes librairiesgraphiques.Envoiciquelques-unes:
» Mesa/OpenGL:fonctionsdeproductiond'élémentsvisuels(de
rendu)engéométriebitmap(mosaïquedepoints).
» Cairo:fonctionsdeproductiond'élémentsvisuelsengéométrie
vectorielle(ordresdetracés).
» GTK+:interfaceutilisateurfenêtréefondéesurCairo.
» WebKit:Moteurderendugraphiquedespagesweb.
Leskitsdedéveloppement(SDK)L'adoption massive du concept de fonction préprogrammée a donné naissance auconceptdekitdedéveloppementdelogicielsouSDK(SoftwareDevelopmentKit).
Un SDK est constitué d'un jeu de librairies de fonctions et de classes avec uneinterface clairement normalisée : l'interface de programmation d'application API(Application Programming Interface). Cette interface régit les conditions danslequelles votre programme peut appeler les fonctions. S'y ajoutent des règles derédactionet desoutilspour lamise aupoint.Souvent, un atelierdedéveloppement(IDE)estproposé,sansêtreobligatoire.VoiciquelquesSDKrépandus:
» WinSDK:PourcréerdesprojetspourMicrosoftWindows.
» JDK:PourconcevoirdesprogrammesenlangageJava.
» UbuntuSDK:PourcréerdesapplicationssousUbuntuLinux.
» XBoxDK:PourécriredesjeuxpourlaconsoleXBox.
» AndroidSDK:PourtouslesappareilssousAndroid.Notamment
exploitédansl'atelierEclipse.
» IOSSDK:PourlestelliphonesettablettesApple.Exploitédans
l'atelierXCode.
Dans le secteur du développement Web, les navigateurs modernes sont dotés decapacitésintéressantespourunprogrammeur:lelangageJavaScript,undébogueur,unanalyseur d'arborescence DOM pour les pages HTML, sans compter les nouvellescapacités de la version 5 du langage HTML. Nous y reviendrons à la fin de laprochainepartie.
Demanièregénérale,toutnouveausystèmeouappareildoitfournirdespointsd'accèssous forme d'interface et de librairies pour permettre à des développeurs d'encontrôler le fonctionnement. Sans SDK, un programmeur extérieur au cercle desconcepteursdusystèmeoudel'appareilnepeutpasdevinercommentl'utiliseretluitrouverdenouveauxdomainesd'usage.
P
Chapitre13Structuresetpointeurs
DANSCECHAPITRE:
» Toutestdanstout:lesstructures
» Tableauxdestructures
» Regarderledoigtoulalune:lespointeurs
ourcloreenbeautécettepartieconsacréeauxfondamentauxdesinfolangages,nousallonsvoir undernier typededonnéesqui offredespossibilités énormes. Il estd'ailleurs à la base des nouveaux langages nommés langages objets que nous
verronsdanslaprochainepartie.
Puisque nous savons que dans un ordinateur, si ce n'est pas une valeur, c'est uneadresse, nous terminerons, mais sans nous aventurer trop avant, par une rapidedécouverte du concept de pointeur, une variable dans l'esprit deMagritte : « cettevaleurn'estpasunevaleur».
Ce chapitre est déclaré facultatif. Son contenu peut avoir des effets réels sur l'étatchimiquedevosneurones.Cependant,nepaslelirevousempêcherad'accéderàunemaîtriseacceptabledesconceptsdetousleschapitresprécédentsetsuivants.
Desbâtimentslogiciels:structLes notions rencontrées depuis le début de cette partie suffisent à résoudre de trèsnombreux problèmes.Mais comment regrouper sous un nomglobal des données detypesdifférents?Letableau[]nelepermetpas.Enguised'exemple,supposonsquenous voulions modéliser une collection de disques vinyles rares avec quatrevariables:
» Artiste
» Titre
» Annéedeparution
» Cote
Nousprévoyonsun tableauchaînepour l'artiste et le titrede l'album,unnumériqueentier pour l'année et un flottant pour la cote. Rappelons comment nous devrionsdéclarercesvariablesdefaçonclassique,isolée:
chartArtiste[20];
chartTitre[20];
unsignedintnParu;
floatfCote;
Vousdevinezdéjàquepourgérerdeuxdisques, ilfaudraitcréerunedeuxièmesériede quatre variables, ce qui devient inutilisable pour dix et impensable pour centdisques.
Le mot clé réservé par le langage C pour regrouper ces quatre types de donnéesdifférentseststruct.Aladifférencedetouslesmotsclésdetypesdevariablesvusjusqu'ici, cemot clé ne sert pas à déclarer unenouvelle variable qui serait ensuiteimmédiatementutilisable.
Lemotcléstructsertàdéfinirunnouveautypededonnéesquiestunestructurespécifique.Sadéfinitionn'entraîneaucunecréationdevariable.
Si l'on considère les données simples comme atomiques, un type structure est unemolécule.
Pourexploiterunestructure,ilfauttravaillerentroistemps:
1. créerladéfinitiondunouveautypestructure;
2. déclareruneoudesvariablesdecenouveautype;
3. citerdefaçonqualifiéelesmembresdelastructurepoury
accéderenlectureetenécriture.Quandellesfontpartied'un
ensemble,cesvariablessenommentdeschamps(fields)oudesdonnéesmembres.
Quic'estcetype?Voyonscommentdéfiniruntypestructureenpartantdesasyntaxeformelle:
structnomtype{
type_simple1nom_var1;
type_simple2nom_var2;
//etc.
};
Ils'agitencored'unblocentreaccolades.Mais répétons-nous,cette fois-ci,cen'estunedéfinitionnidevariable,nidefonction.C'estunnouveautypepersonnel.Vousnepouvez vous en servir pour créer des variables que dans le même texte source (àmoinsdelerendrepublic,maisc'estuneautrehistoire).
Pourlenomdutype,vouspouvezvoirlargeafinderestertrèslisible,carcenomneseracitéqu'unefoispourchaquedéclarationdevariable.
Touslestypessimplessontacceptésdansunestructure,mêmelestableaux.
Leconceptdestructureoffreunénormeintérêtpourleprogrammeur,carilpermetdemodéliser des informations du monde réel de façon plus naturelle. Voici un typestructurepermettantderegrouperlesdonnéesd'undisquedelacollection:
structtypeVinyle{
chartArtiste[20+1];
chartTitre[20+1];
intnParu;
floatfCote;
};
Unedéfinitiondestructuresetermineparunpoint-virgule!
Dansunedéfinitionde structure, lesaccolades jouentun rôleplusprochedecellesutiliséesaveclestableauxpourciterlasériedevaleursinitiales.
D'ailleurs, la structure suivante est acceptée, même si elle n'a qu'un intérêtpédagogiquepuisqu'ellenecontientqu'unélément:
structsolo{intx;};
Les accolades et le second point-virgule sont obligatoires, même avec un seulmembre.
FIGURE13.1:Typestructureetimplantationenmémoire(pseudo-valeurs).
Vousremarquezquedansl'exempleplushaut,nousavonsprissoindenommernotrestructuretypeVinyle.C'estunnouveautype.Pourlechoixdunom,lesrèglessontlesmêmesquepourlesidentificateursdevariablesetdefonctions.
DuvirtuelauréelUnefoisletypestructuredéfini,nouspouvonspasseràlaphaseutile:déclarerunevariablecommeétantdecetype.
structnomtypenomvariable;
Notezuneautredifférenceaveclestypesuniversels:ilnesuffitpasdeciterlenomdevotrenouveautype.Ilfautrépéterlemotcléstruct.
Ilexisteunmoyend'éviterderépéterlemotstruct,maiscelarendletextemoinslisible.Celaconsisteànommerdesnomsdetypesdérivésavantl'accoladefinaleducorpsdedéfinitiondutype.
Dansnotreexemple,nouscommençonsnotrecollectiondevinylesavecdeuxalbums,vin1etvin2:
structtypeVinylevin1,vin2;
Cette simple déclaration suscite l'existence de huit nouvelles variables, quatre parstructure.Dorénavant, de l'espacemémoire est réellement occupé,mais les valeursquis'ytrouventsontsanssignification.
La première action à prévoir sur une nouvelle structure, comme pour toute autrevariabled'ailleurs,estuneopérationd'écriturepourquelecontenuprennesens.Mais
commentprocéderàcesaffectations?
FIGURE13.2:Typestructureetstructuredanslefichierexécutable.
Montrerlechemin(lepoint)Une structure est un ensemble qui possède des variables internes. Ce sont donceffectivementdesdonnéesmembres(delastructure).
Accéderàunedonnéemembresupposedeciterlastructurepuislemembreavecunpointd'articulation:
nomVarStructure.nomVarInterne
Appliquonscettetechniqueàunobjetvinyle:
vin2.tArtiste="BobbyLapointe";
vin2.tTitre="Comprendquipeut";
vin2.nParu=1969
vin2.fCote=89.00
Cesontdesaffectationsclassiques,hormislerôledequalificateurquejouelenomdelastructure.
Voici un court premier exemple qui définit un autre type structure, déclare unevariable de ce type et y stocke des valeurs. Le nom patron a été choisi poursuggérerlanotiondemodèle,commeunpatrondecouture.
LISTING13.1Textesourcestruct_simple.c
//struk_simple.c
#include<stdio.h>
#include<string.h>
structpatron{
intx;
charnom[80+1];
};
intmain()
{
structpatronstrukVar;
strukVar.x=12;
strcpy(strukVar.nom,"EmileJacotey");
printf("Matricule:%d\n",strukVar.x);
printf("Nom:%s\n",strukVar.nom);
return(0);
}
Initialisationmanuelled'unestructureIlestpossibled'implanterdesvaleurs initialesdansunevariablestructureenmêmetempsqu'elleestdéclarée:
structtypeVinylev3={"Toto","Bestof",1982,
12.00};
ouaveclesnomsdeschampspréfixésparlepoint:
structtypeVinylev4={.tArtiste="Toto",\
.tTitre="Inlove",\
.nParu=1982,\
.fCote=12.00};
Remarquezl'utilisationdelabarreobliqueinversepourgarantirquelesautdelignenesoitpasprisenconsidérationparl'analyseur.
Il est impossible de spécifier des valeurs initiales pour les variables dans ladéfinitiondutypestructure.Cen'estpasunevariable,maisunedéfinitiondetype:oùpourrait-onstockercesvaleurs?
TransmettreunestructureàunefonctionRapidement, la question se pose : comment transporter un aussi volumineux colisd'unefonctionàuneautre?Toutescesvariablesinternes,ilnefaudraitpasenperdreenchemin.
En vérité, rien de plus simple : vous citez le nom de la variable structure lors del'appel.C'estdans leprototypeet la têtededéfinitionde la fonction receveusequec'estpluscomplexe.Voiciunprototype:
voidmontrerS(intnum,structtypeVinyles);
Cette fonction attend deux paramètres, dont une structure. Il faut répéter lemot cléstructetlenomdutype.Lamentiond'unepseudo-variable(s,ici)estfacultative,maisconseilléepourêtrecohérentaveclalignedetêtededéfinitionquidoitlaciterpourpouvoirs'enservirdanslecorpsdefonction:
voidmontrerS(intnum,structtypeVinyles){
//Corpsdedéfinitiondefonction…
Voicicommentappelercettefonctionavecunestructure:
montrerS(98,vin2);
Lenomde la variable structure est cité tel quel, sans complément.Notez que cettetechnique provoque une copie des valeurs de la structure.Cela ne permet pas à lafonction receveusedemodifier les valeurs de la structure, seulement de s'en servirpourtravailler.Enfindechapitre,nousverronscommenttransmettreunpointeursurunestructureafindepouvoirmodifiersoncontenu.
Nous en savons assez pour parcourir un exemple complet.Les lignes remarquablessontimpriméesengras.
LISTING13.2Textesourcestruk_vinyle.c
//struk_vinyle.c
#include<stdio.h>
#include<string.h>
intdsq=19;
structtypeVinyle{
chartArti[20+1];
chartTit[20+1];
intnParu;
floatfCote;
};
voidsaisir_t(char*);
voidmontrerS(intnum,structtypeVinyles);
intmain(void)
{
dsq++;
structtypeVinylevin1;
structtypeVinylevin2={"ScottLaFaro","Best
of",\
1957,142.50};
structtypeVinylevin3={.tArti="Toto",\
.tTit="Inlove",\
.nParu=1982,\
.fCote=12.00};
montrerS(98,vin2);
montrerS(99,vin3);
strcpy(vin1.tArti,"\n\nNomdel'artisteoudu
groupe");
saisir_t(vin1.tArti);
strcpy(vin1.tTit,"Titredel'albumpastroplong");
saisir_t(vin1.tTit);
printf("\nParuen:");
scanf("%d",&vin1.nParu);
printf("\nCote:");
scanf("%f",&vin1.fCote);
montrerS(01,vin1);
}
voidsaisir_t(char*tA){
printf("%s:",tA);
scanf("%s",tA);
}
voidmontrerS(intnum,structtypeVinyles){
printf("\n====\nDisqueNo:%d\n",num);
printf("Artiste:%s\n",s.tArti);
printf("Titre:%s\n",s.tTit);
printf("Parution:%d\n",s.nParu);
printf("Cote:%5.2f",s.fCote);
}
Cetexemplene suffit pas à répondreànotrebesoin :gérerunevraie collectiondestructures.Pourrait-oncréer toutunélevagede structures sous formed'un tableau?Après tout, le tableaun'acceptequ'un type, et nousn'avonsbesoinqued'un type enplusieursexemplaires.
Uneméga-structureRiennes'opposeàl'idéedeconstitueruntableaudestructures.Nonseulementc'esttrèssimple,maiscelaouvredesuperbespossibilités:
structpatronskGens[10];
LetableauskGenscontientdixstructuresdumêmetypepatron.Sicetypedéfinitunmembrenom,pourpeuplerlechampnomdelatroisièmestructure,nousécrivonsceci:
skGens[2].nom="JeanBraye";
Voiciuncourtexempled'application.
LISTING13.3Textesourcestruk_tablo.c
//struk_tablo.c
#include<stdio.h>
#include<string.h>
structpatron{
intx;
charnom[80+1];
};
char*listeNom[10]={"Gary","Pierre-Yves","Michel",
\
"Emile","Othello","Anne",
\
"Benoit","Martine","Eric",
\
"Floriane"};
intmain()
{
intndx;
structpatronskGens[10];
for(ndx=0;ndx<10;ndx++){
skGens[ndx].x=(ndx+10);
strcpy(skGens[ndx].nom,listeNom[ndx]);
}
for(ndx=0;ndx<10;ndx++){
printf("Matriculedu%d:%d\n",ndx,
skGens[ndx].x);
printf("Nom:%s\n",skGens[ndx].nom
);
}
return(0);
}
Lesrèglesd'écrituredestableauxs'appliquent.Voiciunextraitquiconstruituntableaude 30 structures, chacune étant elle-même constituée de 80 structures de troisvariablessimples:
structtyPixel{
unsignedcharrouge;
unsignedcharvert;
unsignedcharbleu;
};
structtyLigne{
structtyPixelColo[80];
};
structtyLignetMozaik[30];
Voicicommentécriredans l'élément rougede la13estructureColodu4e tableautMozaik:
tMozaik[3].Colo[12].rouge='a';
(Letextesourceestdanslefichiermozaik.c.)
Ondiraitdesobjets?Nousverronsdans laprochainepartieque leconceptd'objetestdirectementdérivédeceluidestructure:
1. Ladéfinitiondutypestructureressembleàladéfinitiond'une
classe.
2. Ladéclarationd'unevariabledecetypestructurecorrespond
àlacréationd'unobjet(uneinstancedeclasse).
La principale différence est qu'un objet réunit des données et des fonctions alorsqu'unestructureneregroupequedesdonnées.
STRUCTETMALLOC()
Lorsquevousprévoyezdemettreenplaceungrandvolumededonnéesavec
desstructures, il fautenvisagerde les implanterdans lazonedemémoireà
gestiondynamique,enutilisant les fonctionsmalloc()etfree(). Vousen
apprendrez plus dans tout bon livre dédié au C tel que « Apprendre à
programmerenCpourlesnuls»danslamêmecollection.
Lemondesecretdes*pointeursDemandez à n'importe quel programmeur de n'importe quelle culture, de n'importequelpays:«Parlez-nousdevotrevécuaveclespointeurs.»
Dans un ordinateur tel qu'ils sont conçus de nos jours (revoir la Partie 2), tout estvaleur, les actionscomme lesdonnées.Tout est stockédans l'espacemémoire, saufpendantlebrefmomentoùlesactionssontdigéréesparleprocesseurpourmodifierles données copiées dans les minuscules mémoires internes de ce processeur, lesregistres.
Toutes cesvaleurs, données comme instructions encodemachine, circulent entre leprocesseuretlamémoireparuncanaldédié,lebusdedonnées.
Pouraccéderàchaquecellulemémoire,leprocesseurconfigureunevaleurnumériquesur un bus séparé du bus de données, le bus d'adresses. En temps normal, leprogrammeurnes'occupepasdecequiycircule,toutcommeons'intéresserarementà l'adresse indiquée sur l'enveloppe d'un courrier que l'on reçoit (sauf erreur dedistribution!).
Dans un ordinateur, le modèle de processeur détermine une fois pour toutes lacapacitéd'adressage,c'est-à-direlataillemaximaledel'espacedestockagemémoire.Pour atteindre chacune des cellules de cet espace, il faut pouvoir exprimernumériquementsonadresse.
Unmicro-contrôleurindustriel(contrôleurdelave-lingeparexemple)secontented'unespacemémoiregérésurdeuxoctets(typeshortduC,soit65536cellules).
LeprocesseurIntel8080d'avril1974possédaitunbusdedonnéessur8bitsetunbusd'adresses sur 16 bits (déjà ! ). Le bus d'adresses d'un processeur d'ordinateurgénérique actuel (AMD/Intel) est doté de 48 lignes d'adressage réelles, mais un
mécanismeincontournableettropcomplexepourêtreexpliquéicitraduitlesadressesphysiquesenadressesvirtuelles.
32OU64BITS?
Pourun compilateurC (ouC++)32bits, la tailledespointeursestdequatre
octets. Pour un compilateur 64 bits, la taille des pointeurs doit être de huit
octets,alorsquecen'estpasobligatoirementlecasdutype«natif»intqui
enoccupesoitquatre,soithuit,mêmeenmode64bits.
Pournepasallertroploin,considéronsquevotreprogrammeaaccèsà4096Modemémoire,cequicorrespondàdesadressessur32bits(quatreoctets).
Revoyons d'abord comment sont stockées les valeurs en mémoire, sans l'aide duconcept de pointeur. Nous avons remplacé dans le texte source les appels àprintf()parlesrésultatsqu'elleaffiche.
LISTING13.4Textesourceptr_adresses.c,sansprintf().
//ptr_adresses.c
#include<stdio.h>
intmain()
{
charcVal=64;
shortsVal=2048;
inti;
chartabChar[]={65,66,67,68,69,70,71,72};
inttabInt[]={65,66,67,68,69,70,71,72};
//cVal=64(@)&cVal=2686695Taille1
//sVal=2048&sVal=2686692Taille2
//Aveccharsur1octet(sizeof(char))
for(i=0;i<8;i++){
//tabChar[i]=65(A)&tabChar[i]:2686728
//tabChar[i]=66(B)&tabChar[i]:2686729
//tabChar[i]=67(C)&tabChar[i]:2686730
//tabChar[i]=68(D)&tabChar[i]:2686731
//tabChar[i]=69(E)&tabChar[i]:2686732
//tabChar[i]=70(F)&tabChar[i]:2686733
//tabChar[i]=71(G)&tabChar[i]:2686734
//tabChar[i]=72(H)&tabChar[i]:2686735
}
//Avecintsur4octets(sizeof(int))
for(i=0;i<8;i++){
//tabInt[i]=65&tabInt[i]:2686696
//tabInt[i]=66&tabInt[i]:2686700
//tabInt[i]=67&tabInt[i]:2686704
//tabInt[i]=68&tabInt[i]:2686708
//tabInt[i]=69&tabInt[i]:2686712
//tabInt[i]=70&tabInt[i]:2686716
//tabInt[i]=71&tabInt[i]:2686720
//tabInt[i]=72&tabInt[i]:2686724
}
return(0);
}
Nousavonsdéfinideuxtableaux:lepremierpourunetaillecharetl'autrepourunetailleint.Observezbienlaprogressiondesadressesd'unélémentausuivant.
PourtabChar,onprogresseparpasdeunoctetetpourtabIntparpasdequatreoctets. Souvenez-vous de cemécanisme lorsque nous allons déclarer notre premierpointeur.
Pour une raison pédagogique, nous avons choisi de faire afficher les adresses auformat décimal avec le formateur %d et non le formateur %p spécifique auxpointeursquiutiliselanotationhexadécimalemoinsfacileàlire.Sivousexplotezlesadresses,utiliseztoujours%p.
Lanotiondepointeurperturbebeaucoupdepersonnesparcequ'ellebriseunebarrièreentrelesdeuxcanauxdedialogue:lebusdedonnéesetlebusd'adresses.
Lepointeurnecontientpasune«valeur»ausensstrict,maisunevaleurtechniquequivatransitersurlebusd'adressespourpréparerlaprochainelectureouécritured'unedonnéequi,elle,transitesurlebusdedonnées.
C'est un peu comme en biologie : des milliards d'êtres sont fondés d'abord sur lamerveille de technologie qu'est la cellule vivante sans lui rendre spécialementhommage.Sauriez-voussentirchacunedevoscellulesindividuellement?
De même, les langages modernes (objets, fonctionnels, etc.) utilisent de façonintensivelespointeurssansqueleprogrammeurenaitconscience.C'estcequenousverronsdanslaprochainepartie.
Pourquoiprendrecesrisques?Avecunpointeur,toutdevientpossible,mêmelepire.L'analyseurnepeutpastraquerles fautes de pointeurs puisque l'adresse ne sera connue qu'au dernier moment,pendant l'exécution, et dans certains cas, il sera trop tard. Si les pointeurs sont sidangereux,pourquoiautoriserleurutilisation?
Unevariable est un symbolepourune adressemémoire, commenous l'avonsvu endébutdepartie.Le faitdeciter lavariabledonneaccèsà lavaleur trouvéeà cetteadresse. Cela pose problème lorsque vous voulez modifier cette valeur depuis unendroitduprogrammeoùlavariablen'estpasaccessible.
Les pointeurs servent donc d'abord àmodifier depuis une autre fonction le contenud'unevariablesimple,d'untableauoud'unestructureinaccessibleparcequedéclaréedanslafonctionquil'appelle.
Pouréviterlespointeurs,laseulesolutiondevientrapidementinutilisable:déclarertouteslesvariablesendehorsdetoutefonction,mêmedemain(),doncentantquevariablesglobales. Ildevientalors trèsdifficilededevineràquelsendroitschaquevariableestmodifiée.
Avecunpointeur, toutreste lisible.Vousinformezlafonctionreceveusedel'endroitoù se trouve la valeur à traiter ; elle modifie la valeur puis rend le contrôle. Lafonctionquil'aappeléevoitlanouvellevaleur.
LespointeurssontoffertsentailleuniquePuisqu'un pointeur doit permettre d'accéder à n'importe quelle cellule de l'espacemémoire, toutes les variables pointeurs ont la même taille. Dans la suite, nousutilisonsdespointeurssur32bits,doncquatreoctets.
Enréalité,desoptimisationssontappliquéespourproduirelefichierexécutableetlecharger.Lorsquelacibled'unpointeurestàuneadressetrèsproche(parexempleàmoinsde127octetsavantouaprès,commec'estlecasdanslesboucles),lepointeur
estraccourcisurunoudeuxoctetsetdevientrelatif,maisrestonsdanslecasgénéral.
Préparerunpointeursupposetoujoursdeuxétapes:
1. Déclarationdupointeurenl'associantautypedesacible
future.
2. Armementdupointeurenlefaisantpointersursacible.
1)Déclarezvotrepremier*pointeurEn langageC,vousne spécifiezpasunnomde type spécial commeonpourrait s'yattendre, du stylepointermonPointeur; . Puisqu'un pointeur n'a d'intérêtques'ilauneciblesurlaquelleilpointera(notezl'emploidufutur),cequicompte,c'estdeconnaîtrelatailledecettecible.
Voicidoncunedéclarationdepointeursurunevariabledetypedouble.
double*nomPointeur;
C'est extrêmement simple. Vous plongez dans une autre dimension par la simplementiondel'astérisque.Quelssontleseffetsdecettedéclaration?
C'est une variable. Son nom est nomPointeur (une bonne pratique consiste àchoisirunpréfixepourlesnomsdepointeurs;dansnosexemples,nousavonschoisiptr).
Cette variable occupe de l'espace mémoire. Nous avons dit plus haut que poursimplifier(etleconceptdepointeurslemérite),touslespointeursdecechapitresontsurquatreoctets.
Silavariableoccupedel'espace,elleauneadressemémoire.Onn'ycoupepas.Unpointeurvacontenir(encoreaufutur)uneadresse,maisilenaunelui-même.(Ensoi,cela n'a aucune importance, mais c'est ce qui permet d'envisager des pointeurs depointeurs.)
Pourquoiassocieruntypedevariableàunpointeur?Lepointeurdeladernièredéclarationestassociéàuneciblequivas'étendresurhuitoctets (typeflottantdouble).L'adressequ'ilvacontenirseracelledupremierdeshuit octets, mais unmécanisme caché très utile profite de cette précision. Si vousfaitespointerlepointeursuruntableaudevaleurschar,enajoutantlavaleurunau
contenudupointeur,lecontenuvaautomatiquementcroîtredeunoctet,etpointersurledeuxièmeélémentdutableau,quiestjusteaprèslepremier,doncunoctetplusloin.Nousyreviendrons.
Pour lemoment, lecontenudupointeurestcommepourunevariableclassiquesanssignification,maisilestbienplusdangereux.Sivousutilisezcepointeurdanssonétatbrut,vousdemandezd'accéderàuneadressemémoiretotalementimprévisible.C'estcequipeutprovoquerl'arrêtbrutalduprogramme.
TYPE*NOMPOINTEUROUTYPE*NOMPOINTEUR?
Lesprogrammeurssontpartagésquantàdécidersil'astérisquedoitêtrecollé
au nom du type ou au nom du pointeur. Deux lectures sont possibles et
correctes.Ladéclarationpeutselire:
nomPointeurestdutype«pointeur_sur_type»doncsur«type*»(pourle
distinguerdelamention«type»,seule,sanssuffixe).
Mais nous verrons plus loin que pour obtenir la valeur stockée à l'adresse
pointée, on écrit *nomPointeur. On peut donc aussi comprendre la
déclarationcomme:
«lavaleurpointée»(*nomPointeur)estdutypedirect«type».
Lesdeuxécrituressontacceptéesetlesdeuxraisonnementsjustes.
2)ArmezvotrepremierpointeurPoursortirleplusvitepossibledecettesituationinstablequ'ondésignesousletermede«pointeurerrant»,ilfautécriredanslavariablepointeurl'adressed'unevariabledirectedutypeapproprié.
Noussavonsque l'onobtient l'adressed'unevariable simpleavec l'opérateur& enpréfixe(saufpourlestableauxquisontdespointeurscachés,auquelcaslenomsuffit,sanspréfixe).Voicicommentarmerunpointeursurvariablesimple,puisunautresuruntableau:
ptrTVA=&varTVA;
ptrTABREM=tabloRemises;//Préfixe&inutile
3)UtilisezvotrepremierpointeurPour accéder au contenu du contenu (ce qui est stocké à l'adresse stockée dans lepointeur),lasyntaxeestlamêmequedansladéclaration,maissanstype.Enlecture,puisenécriture:
variableReceveuse=*nomPointeur;
*nomPointeur=variableSource;
Certainsparlentdedé-référencementoud'accès indirect.Récapitulonscelaavecunpremierexempledanslequelnousremplaçonstouslesappelsàlafonctiond'affichageprintf()pardescommentairesmontrantunexempledevaleurréelle.(Lesappelssontprésentsdanslefichierd'exempletéléchargeable.)Ilestnormalquelesadresseschangentd'uneexécutionàl'autre.
LISTING13.5Textesourceptr_hegger.c
//ptr_NULL.c
#include<stdio.h>
intmain()
{
doubleHegger=12345.6789;
double*ptrH;//1
//=NULL;pourfairetairel'analyseur
intadresse_ptrH=(int)&ptrH;//2
//Adresse&ptrHerrantsanscible:2686740
//Taillesizeof(ptrH):4octets//3
//Avarieseveresivoustentezceci:
//catastrophe=*ptrH;
//Ciblagedelastructureparlepointeur
ptrH=&Hegger;//4
//Utilisation
intvaleur_ptrH=(int)ptrH;
//ValeurdeptrH(adressecible):2686744//5
doublevalcible_ptrH=*ptrH;//6
//Valeurde*ptrH(contenucible):12345.68
//Taillesizeof(*ptrH):8octets//7
return(0);
}
Penchons-noussurleslignesnumérotéesparcommentairedeligne:
1. Nousdéclaronsunpointeursurvariabledouble.Iln'estpas
encoreutilisable.
2. Nouspouvonsdéjàconnaîtresonadresse,cequiprouvequ'il
existeréellementenmémoire.
3. Justepourvérifier:lavariablepointeuroccupequatreoctets
danslemodèledecompilationchoisi(32bits).
4. Nousécrivonsl'adressed'unevariabledanslepointeur.Il
devientutilisable.Commeunmissile,ilestverrouillésursa
cible.
5. Logiquement,lavaleurdupointeurestbienl'adressedela
variableciblée.Notezquecetteadresseestquatreoctetsplus
loinquecelledupointeur(point2)quis'étendsurquatre
octets.
6. Nousutilisonslepointeurpourrécupérerlavaleurnumérique
detypedoublesituéeàl'adresseviséeparlepointeur.
7. Cettevaleurestbiensurhuitoctets,puisquenousavons
déclaréunpointeursurdouble.
Voicilerésultataffiché:
//Adresse&ptrHerrantsanscible:2686740
//TailledeptrH:4octets
//ValeurdeptrH(adressecible):2686744
//Valeurde*ptrH(contenucible):12345.68
//Taillede*ptrH:8octets
Après avoir lu cette explication, doit-on continuer à croire que la mécanique despointeursestdifficile?Ilestcertainqu'ellesupposederestercalmeetimposeunpeudegymnastiquecérébrale,maisles«cérébrologues»conseillentdefaireunpeudesportcérébraltouslesjours.
Voyons maintenant le grand intérêt des pointeurs avec les tableaux puis avec lesstructures.
PointeursettableauxL'accès à un élément de tableau se base sur la notation [indice entre crochets]. Enfaisantpointerunpointeursurledébutdutableau,onpeutensuiteparcourirletableaud'uneautre façon. Ildevientalorspossibledeprogresserenajoutantouenenlevantdesunitésàlavaleurdupointeur.
Nousavionsparléplushautdelaraisonpourlaquelleonnedéclarepaslepointeuravecuntypepointeur,maisavecletypedesacible.C'estgrâceàlaconnaissancedelatailleunitairedelaciblequel'adressecontenuedanslepointeurpeutvariercommeparmagiedubonnombred'unités.Unexemple.
LISTING13.6Textesourceptr_tabshort.c
//ptr_tabshort.c
#include<stdio.h>
#defineSZsizeof
intmain()
{
shorttabSho[]={65,66,67,68,69,70,71,72};
inti;
short*ptrT=tabSho;
printf("//Tableaudeshortsur%doctets\n",
SZ(short));
printf("//ptrTvaut%d\n\n",ptrT);
for(i=0;i<3;i++){
printf("//tabSho[i]:Contenu=%d\n",
tabSho[i]);
printf("//&tabSho[i]:Adresse=%d\n",
&tabSho[i]);
intpad=(int)(ptrT+i);
printf("//(ptrT+i)=%d+(%d*2)=%d\n",ptrT,i,
pad);
shortpva=*(ptrT+i);
printf("//Contenu*(ptrT+i)=%d\n\n",pva);
}
return(0);
}
C'estàdesseinquenousavonschoisidepartird'untableaudevaleursshort.Celapermetdemieuxdistinguerlamanipulationdesadressesdecelledescontenus.Voicilesrésultatsaffichés.
//Tableaudeshortsur2octets
//ptrTvaut2686720
//tabSho[i]:Contenu=65
//&tabSho[i]:Adresse=2686720
//(ptrT+i)=2686720+(0*2)=2686720
//Contenu*(ptrT+i)=65
//tabSho[i]:Contenu=66
//&tabSho[i]:Adresse=2686722
//(ptrT+i)=2686720+(1*2)=2686722
//Contenu*(ptrT+i)=66
//tabSho[i]:Contenu=67
//&tabSho[i]:Adresse=2686724
//(ptrT+i)=2686720+(2*2)=2686724
//Contenu*(ptrT+i)=67
Pourgagnerunpeuenlargeurdanslecodesource,nousavonsdéfiniunaliasSZpoursizeof.C'estunesimplerecherche/remplacement.
Nous créons le pointeur tout en lui affectant sa cible en une seule ligne. C'est laméthodeconseilléelorsquec'estpossible:
short*ptrT=tabSho;
Rappelons que pour un tableau, l'opérateur& est inutile.Unnomde tableau est unpointeur.
Sivoustombezsurleparagraphequisuitsansavoirlutoutecettepartiedansl'ordre,vousallezavoirdumal.
Lisezcalmementl'instructionsuivante:
intpad=(ptrT+i);
Elle récupère la valeur résultant d'une addition entre la valeur du pointeur ptrT(uneadresse)etl'indicedebouclei.Maisilyauneastuce:l'indicen'estpasutilisécomme demandé, mais automatiquement multiplié par le nombre d'octetscorrespondantautypedelavariablepointé,icishort.
En réalité,nousavonsajoutéunpréfixede transtypage(int)devant l'expressionpourquel'analyseursoitcontent.Eneffet,surnotremachine,letypeintalamêmetaillequele«type»pointeur,maiscen'estpasnécessairementlecas.C'estpourquoil'analyseurémetunavertissement.
En revanche, cette instruction récupère un contenu d'adresse, donc une valeur. Lavariablereceveusedoitlogiquementcadreravecletypeducontenu,icishort.
shortpva=*(ptrT+i);
Cesontlàlesbasesdecequel'onappellel'arithmétiquedespointeurs.Enprenantlapeinedecomprendrecettemécanique,vouspourrezensuitevousaventurerdansdesniveauxd'abstractionsupérieursavecdesolidesfondations.
PointeursetstructuresNousavonsdécouvertendébutdechapitrequel'accèsàunmembred'unestructuresebasaitsurlanotationpoint(nom_structure.nom_membre).
Il est également possible de cibler la structure avec un pointeur en lui affectantl'adressedelastructure(avec&).Ilfautquelepointeursoitdéclarédutypeadéquat,doncdutypestructuredel'objetsurlequelilfaudralefairepointer.
LISTING13.7Textesourcepstruk_simple.c
//pstruk_simple.c
#include<stdio.h>
#include<string.h>
structpatron{
intx;
charnom[80+1];
};
intmain()
{
structpatronstrukVar;
structpatron*ptr;
strukVar.x=12;
strcpy(strukVar.nom,"EmileJacotey");
//Ciblagedelastructureparlepointeur
ptr=&strukVar;
intiMatri=ptr->x;
printf("//Matricule:%d\n",iMatri);
char*sNom=ptr->nom;
printf("//Nom:%s\n",sNom);
return(0);
}
Nousdéfinissonslenouveautypestructure:
structpatron{
intx;
charnom[80+1];
};
Nouscréonsunevariable(instance)decetypestructure:
structpatronstrukVar;
Nousdéclaronsunpointeurdumêmetypestructure:
structpatron*ptr;
Nousarmonslepointeurpourqu'ilciblelavariable.Aladifférencedestableaux,ilfautindiquerl'opérateurd'adresse&enpréfixed'unnomdestructure:
ptr=&strukVar;
Nous pouvons maintenant utiliser indifféremment la notation point ou une nouvellenotation avec le pointeur. L'opérateur correspond au couple de symboles tiret-supérieur(->).
intiMatri=ptr->x;
PointeursettableauxdestructuresPuisquenoussommesenverve,remplissonschacunedesstructuresd'untableauavecunevaleurentièreetuntableauchaîneetarmonsunpointeurverschaquestructure.
LISTING13.8Textesourcepstruk_tablo.c
//pstruk_tablo.c
#include<stdio.h>
#include<string.h>
structpatron{
intx;
charnom[80+1];
};
char*listeNom[10]={"Gary","Pierre-Yves","Michel",
\
"Emile","Othello","Anne",
\
"Benoit","Martine","Eric",
\
"Floriane"};
intmain()
{
intndx;
structpatronskGens[10];
structpatron*pskGens[10];
for(ndx=0;ndx<10;ndx++){
skGens[ndx].x=(ndx+10);
strcpy(skGens[ndx].nom,listeNom[ndx]);
pskGens[ndx]=&skGens[ndx];
}
for(ndx=0;ndx<6;ndx++){
printf("\nMatricule%d:%d\n",ndx,pskGens[ndx]-
>x);
char*sTempo=skGens[ndx].nom;
printf("//skGens[ndx].nom=%s\n",sTempo);
sTempo=pskGens[ndx]->nom;
printf("//pskGens[ndx]->nom=%s\n",sTempo);
}
return(0);
}
Voiciunepartiedel'affichagerésultant:
Matricule0:10
//skGens[ndx].nom=Gary
//pskGens[ndx]->nom=Gary
Matricule1:11
//skGens[ndx].nom=Pierre-Yves
//pskGens[ndx]->nom=Pierre-Yves
//etc.
AvecuntableaudepointeurspskGens[]suruntableaudestructuresskGens[],vousconstatezqu'ilestabsolumentégald'écrire:
skGens[ndx].nom
et
pskGens[ndx]->nom
Vous remarquez que nous armons chaque pointeur dans une boucle en y stockantl'adressedudébutdelastructuredemêmeindice:
pskGens[ndx]=&skGens[ndx];
TransmettreunestructureLe pointeur est l'outil indispensable pour transmettre l'adresse d'une structure d'unefonctionàuneautreafinquecettedernièrepuissemodifierréellementlesvaleursdelastructure.
Lorsquevoustransmettezuneadresse,lecôtéreceveurdoitcapturercette«valeur»dansunpointeur.Lafonctionreceveusedoitdoncdéfinirunparamètrepointeursurletypestructure:
structsolo{
intx;
inty;
};
intmodifier(structsolo*s);
L'appelàlafonctionréclamel'opérateur&:
modifier(&mSolo);
La fonction receveuse manipule les membres de la structure avec la notationpointeur->:
s->x=4321;
s->y=8765;
Vous remarquezque la fonctionde traitementutiliseunnom localpour la structure,maislesnomsréelsdeschampsdedonnées.Voicil'exemplecomplet.
LISTING13.9Textesourcepstruk_solo.c
//pstruk_solo.c
#include<stdio.h>
structsolo{
floatx;
floaty;
};
intmodifier(structsolo*s);
intmain()
{
structsolomSolo;
mSolo.x=12.00;
mSolo.y=34.00;
printf("Valeuravant:%.2f\t%.2f\n",mSolo.x,
mSolo.y);
modifier(&mSolo);
printf("Valeurapres:%.2f\t%.2f\n",mSolo.x,
mSolo.y);
return(0);
}
intmodifier(structsolo*s){
s->x+=1234.50;
s->y+=5678.10;
return(0);
}
Dansl'appel,noustransmettonsl'adressedelastructure.Nouslarécupéronsdanslepointeur s qui nous permet de changer les valeurs. Inutile de renvoyer la structurepuisquenoussommesintervenussurlavariabled'origine.
Lespointeurssontdesvariables!Une variable pointeur peut changer de valeur,même si cela doit être fait avec desrèglestrèsprécises.L'arithmétiquedespointeursn'estapplicablequedanslecasoùilest certain que les valeurs se suivent en mémoire, ce qui est le cas de chaquedimensiond'untableau(maispasd'unedimensionàl'autre!).
Leprincipalcasdechangementdelacibled'unpointeurestlalisteliée.
Deswagonnets…(unelisteliée)Unelisteliéeestuntypestructuredontundesmembresestunpointeursurlemêmetypestructure.Celapermetde façon trèsélégantedecréerune liste liée,commeuntraindewagonsaccrochéslesunsauxautres.
Chaquewagonestuneinstancedelastructureetcontientunlien(lepointeur)verslewagonsuivantoulavaleurspécialeNULL.
LISTING13.10Textesourcewagons.c
//wagons.c
#include<stdio.h>
#defineNBWAG15
structwagon{
intcontenu;
structwagon*suivant;
};
intmain()
{
structwagontrain[NBWAG];
inti;
for(i=0;i<NBWAG;i++){
train[i].contenu=(i+64);
train[i].suivant=NULL;
if(i>0){
train[i-1].suivant=&train[i];
printf("%c_",train[i].contenu);
}elseprintf("\nLocomotive_");
}
printf("QueueDuTrain\n");
if(!train[NBWAG-1].suivant)
printf("\nFindetrainatteinte!");
return(0);
}
L'exécutiondel'exemplepermetdevoircequiressembleautableauaffichéengaredont vous vous servez pour trouver votre place (le tableau de composition destrains):
Locomotive_A_B_C_D_E_F_G_H_I_J_K_L_M_N_QueueDuTrain
L'exemplesuffitàillustrerleprincipedelalisteliée.Lemembresuivantdechaquewagon contient l'adresse du wagon suivant, sauf le dernier. Pour simplifier, nouscommençons par forcer la valeurNULL dans chaque chaînon puis nous relions leswagonsenécrivantl'adresseduwagonencoursdanslepointeurduprécédent.
Le train devient ensuite utilisablemême sans connaître le nombre dewagons (voirl'exemplewagons3.c),enrebouclanttantquelepointeurversleprochainwagonnevautpasNULL:
while(train[i].suivant!=NULL)
Unelisteliéedeniveauprofessionnelserabienplussophistiquée:
» Lacréationdeswagonsdoitsefairedefaçondynamiquepar
réservation/libérationdeblocsdemémoireaveclesfonctions
malloc()etfree().
» Desfonctionssontàajouterpourpouvoirnaviguerdanslaliste
autrementqu'enmarcheavant,pourajouterunwagonn'importe
oùetenenlever,etpourchercherunwagon.
Toutes cesopérations se résument à lire et écrire despointeurs.Par exemple, poursupprimer un wagon, il suffit d'écrire dans le chaînon du précédent l'adresse dusuivant.Lewagonintermédiairedisparaît.(Maisilfautpenseràrestituerlamémoirequ'iloccupe.)
Pourtoutescesfonctions,desexempleséprouvésetoptimiséssontdisponiblesdanslacommunautédesprogrammeurs.
ConclusiondelapartieStructures et pointeurs constituent le point d'orgue de cette partie. Nous allonsmaintenantnouséloignerdescontraintesmatériellesavecleslangagesorientésobjetsetlaprogrammationpilotéeparévénements.
Ilyaauradesvaleurs,despointeursetdesstructurespartout,maissousdenouvellesformes.Votreprogrammevas'ouvriràsoncontexte, ilvasesocialiseretdialogueraveclesystèmed'exploitation.
IVObjetsetméthodes
DANSCETTEPARTIE
Chapitre14:Fenêtresetévénements
Chapitre15:Programmationorientéeobjets
Chapitre16:SGML,HTML,CSS,JavaScript
L
Chapitre14Programmationpilotéeparévénements
DANSCECHAPITRE:
» Findudactylocène
» Desfenêtresetunarbitre
» Resteràl'écouteetbienréagir
e clavier est le descendant direct du téléscripteur qui servait à composer lesmessages télégraphiques. Ce mode de communication écrite reste efficacepuisqu'unordinateurproposedesservices(desprogrammes)quiportentdesnoms.
Jusqu'auxannées1990,ondialoguaitavecunordinateurviaunclavier.Danscemode,lepremiermottapéestengénérallenomd'unprogrammedontonprovoqueainsilelancement.
COPIERFichierExistantCopieDuFichier
Pour obtenir un service (par exemple, l'affichage de la liste des textes dans undossier),ilsuffitd'invoquerlenomduservice(unesorted'incantation).C'estlemodeappeléCommand-LineInterface(CLI)oumodecommandeaussiappelémodetexte.Maiscetteapprochesupposed'avoirmémorisétoutelapalettedeservicesdontonabesoin.Etcettephased'apprentissageprenddutemps.
Au cours des années 1960, la palette de domaines d'activité pouvant tirer avantagedes ordinateurs a fortement augmenté. En parallèle, le coût des ordinateurs asuffisammentdiminuépourqu'ilsnesoientplusréservésauxplusgrossesentreprises.Lesmini-ordinateurs sont apparus (PDP deDigital, IBM 38, etc.). On notera avecamusementquecequiétaitbaptisé«mini-ordinateur»désignait desmachinesayantaumoinslatailled'unearmoirehauteetpesantpresqueunetonne.
La diffusion desmini-ordinateurs puis desmicro-ordinateurs dans des centaines demilliersd'entreprises(d'abordpouraccélérerlesactivitésdecomptabilité)aentraînéunénormebesoindeformation.Commentaccélérer lapriseenmainsdelamachineparl'utilisateur?
Au départ, l'idée d'une interface pilotée par souris était cantonnée aumonde de larecherche puis à celui des premiers systèmes de création graphique (CAO) pourremplacerledessinindustriel.
DudactylocèneaucliquocèneAncienopérateurradar,DougEngelbartdeStanfordadès1968présentéunemachineavec interface graphique pilotée par souris à trois boutons et liens hypertextes(NLS/Augment).Decettedémonstrationmémorableestné,en1973,leXeroxAltodulaboratoireXEROXPARC(PaloAltoResearchCenter).
Cesinnovationsontconduitaumoded'utilisationactueldesordinateurs,d'abordchezAppleavecsonMacintosh,puischezMicrosoftavecMS-Windows.
Cettenouvellemanièredecontrôlerunemachineaétéunerévolutionautantpourlesutilisateursdeslogicielsquepourlesprogrammeurs.
(DroitsréservésXeroxPARC)
FIGURE14.1:PremièresourisduPARCetinterfaceduXeroxAlto(1968).
LenomadoptépourcetteinterfaceestGUI,quisignifieGraphicalUserInterfaceouInterfaceutilisateurgraphique.Maisl'essentieln'estpasqu'ellesoitgraphique:c'estun véritable écosystème, un environnement dans lequel vous en tant qu'auteur de
programmes venez vous inviter.Un peu comme dans lemonde physique le jour devotrenaissance.
InterfacesgraphiquesetévénementsEnquoiuneinterfacegraphiqueest-elleunerévolutionpourleprogrammeur?
Contrairement à l'approche classique en mode commande, vous ne pouvez plusignorer les autres programmes. Vous allez cohabiter avec d'autres fenêtres, auminimumaveclefonddebureau(Desktop)etavecl'Explorateur(ouleFinder).
Avantd'écrire lapremière lignedevotreprogramme,vousdisposezdéjàde toutunensemblede fonctionspourdialogueravec l'utilisateur.Ces fonctionssont intégréesau système (Windows, MacOS, Unix/X-Window). Alors qu'auparavant le systèmed'exploitationn'était pas visible de l'utilisateur une fois quevotre programmeavaitdémarré, il devient l'intermédiaire obligé entre l'utilisateur et vous (votreprogramme).
Dans cette approche, ce n'est plus votre programme qui écoute les demandes del'utilisateur.C'estlesystème.Cen'estplusvotreprogrammequiaffichedesdonnées(textes,graphiques),c'estlesystème.
Toutunpetitpeuple(fenêtres,boîtes,processus,messages)La surface de l'écran devient l'équivalent d'un bureau (Desktop) géré en tant querectanglegraphiqueconstituéd'uncertainnombredepointsélémentairesenlargeuretenhauteur.Parexemple,unerésolutiontypiqued'écranserade1600pointsenlargeursur 1 200 points en hauteur. La surface de cet écran est distribuée entre plusieursfenêtresquisontposéessurun fond(leplandubureau).Les fenêtressontaffichéesentrelefonddebureauetvous,l'utilisateur,dansunesorted'empilement.
Auseindecettesurface,lepointeurgraphiquepeutêtredéplacéoùbonvoussemblegrâceàunoutildepointage(sourisoustyletd'unetablette).
Danscesconditions,votreprogrammenepeutplusprendrepossessiondelatotalitédelasurface,commec'étaitlecasenmodetexte.Ilestaccueilliparlesystèmequiluiattribueunefenêtrerectangulaire.C'estlesystèmequisechargedesarbitragesentrelesfenêtres.Atoutmoment,uneseuleestaupremierplan.
C'estlafenêtreactive.C'estverscettefenêtrequesonttransmislescaractèresfrappésauclavier.
Lesautres fenêtrespeuventêtrepartiellementou totalementmasquéespar la fenêtreactive. Lorsque vous cliquez dans la surface d'une fenêtre de second plan, vous
indiquezainsiquevousvoulezqu'ellepasseaupremierplan.
Cemécanismevousestsansdouteconnuentantqu'utilisateurdeWindows,deMacOSoudeX-Window(sansS),maisvoyonscequ'ilimpliquepourleprogrammeur.
C'estquoiunefenêtre?Unefenêtresecaractérisepardespropriétésetdescomportements.Ellepossèdeunepositionauseindel'écranetdesdimensionsinitiales.Ellepeutêtremasquée,repliéeoubienvisibleenpartieouentotalité.
Visuellementunefenêtreregroupedeuxparties:
» lapartienon-cliente:c'estlecadredefenêtre,labarredetitreetla
barred'état;
» lapartiecliente:c'estlasurfaceutiledanslaquellevouspouvez
affichervosdonnées.
Sontconsidéréscommefenêtrescequevousappeleznormalementfenêtre,c'est-à-direunezonerectangulaireavecuntitreetdesboutonsd'angle,maisaussitouteslesboîtesdedialoguequisontdessous-fenêtresoufenêtressecondaires.Toutesous-fenêtreestattachéeàunefenêtreprincipalequienestpropriétaire.
Toutefenêtredoitêtrecapablederéagiràdesmessagesquelesystème(ouuneautrefenêtre,maisvialesystème)luienvoie.Ellepeutégalementémettredesmessages.
Vied'unprogrammefenêtréUnprogrammefenêtréconnaîttroisphasessuccessivesdefonctionnement:
1. Audémarrage,leprogrammedemandeausystèmedelui
créerpuisd'afficherunefenêtreprincipale(enstipulantles
dimensionsinitialesetenindiquantsoncontenuinitial).Le
systèmerépondàlademandeetattribueunidentifiantunique
quivaservirauxéchangesultérieurs(un«handle»).
2. Unefoislafenêtreaffichéeaupremier-plan,votreprogramme
entredansuneboucleperpétuelle.Ilattend.Etonnant,non,un
programmequiattend?C'estlesystèmequivadétecterles
événementsquivontseproduire.Pourchaquetype
d'événement,lesystèmeémetunmessagepuislediffusesoità
unefenêtreenparticulier,soitàtouteslesfenêtres
principales.
3. Danschaquefenêtre,laboucled'écoutedesmessagessetient
prêteàréagirauxseulsévénementsquel'auteurdu
programmeajugédignesd'intérêtenécrivantlecoded'une
fonctionappropriée.Lesévénementslesplusfréquentssont
lesactionsaveclasouris.Quandvouscliquez,lepointeurde
sourissetrouveobligatoirement«quelquepart».Les
coordonnéesdel'événementsontrecueilliesettransmises
danslemessage,parexemple«Boutongaucheenfoncé
en200,400».
TransitionversWindowsL'ancienne approche consistant à lancer le programme, à le laisser réaliser sontraitement puis à se terminer reste possible dans un environnement fenêtré. Celasupposedenepasdemanderl'affichaged'unefenêtre,nidemettreenplacelabouclederéceptiondemessages.VoiciunprogrammeminimalsousWindowsquiserviradetransition avec la suite. Il provoque l'apparition d'une boîte de dialogue deconfirmation,maisn'enapasdutoutgérél'affichage.
LISTING14.1:UnprogrammeimpératifpourMS-Windows(ViderCorbeille).
1#include<windows.h>
2intmain(void)
3{
4SHEmptyRecycleBin(NULL,NULL,0);
5return0;
6}
Laligne1nevousestplusétrangèresivousavezlulaPartie1.Nousydemandonsd'insérer lecontenud'un fichier standardquidéfinitnotammentquelquesconstantes.Vousn'aurezjamaisàtoucheràsoncontenu.Cettementionsuffitànouspermettredefaireappelauxfonctionsdeslibrairiesstandarddusystème(ici,MS-Windows).
La ligne 2 déclare le nom de la fonction principale et unique (main). Nous nevoulons pas qu'elle récupère une valeur transmise au démarrage (void) et nousprécisonsqu'ellevarenvoyerunevaleurnumériqueentièreenfind'exécution(int).Leslignes3et6marquentleblocdecodedelafonction,soncorps.
En ligne 4 se trouve la seule action du projet : nous faisons appel à une fonctionstandarddontlenomfrançaispourraits'écrireSHViderCorbeille().LepréfixeSHsymbolisel'outilSHell,c'est-à-direleprogrammequiinterprètedescommandesdegestiondusystèmed'exploitation(créerundossier,copierunfichier,afficherunelistedefichiers,viderlacorbeille).C'estcequirestedumodelignedecommandedel'ancêtreMS-DOS.
Enfin, la ligne 5 provoque (déjà !) la fin d'exécution en renvoyant la valeurnumérique0ausystèmepourconfirmerquetouts'estbienpassé.
Vous avez remarqué que la fonction de librairie désire recevoir trois argumentsd'appel.Dèsquevousvoulezutiliserunefonctionprédéfinie,ilfautalleràlasource,c'est-à-dire la documentation de son créateur. Ici, il s'agit de Microsoft. Sa paged'explications(ellessontsouventnontraduites)nousapprendquelesdeuxpremiersargumentssontfacultatifs.Lepremierpermetd'associerlafonctionàunefenêtre.Ici,nousn'avonspasbesoindefenêtre.Nousindiquonsdonclapseudo-valeurNULL.Ledeuxièmeargumentdoitindiquerunchemind'accèspourlimiterl'effetduvidageauxfichiers effacés qui se trouvaient dans un sous-dossier de ce chemin. Pour viderentièrementlaCorbeille,nousindiquonsNULLaussi.
Letroisièmeargumentestunmasqued'options.Chaqueoptionvautunepuissancededeux (1, 2, 4, 8, etc.). Une option permet de vider la corbeille sans redemanderconfirmation (valeur1ounomSHERB_NOCONFIRMATION),une autredenepasafficherlajaugedeprogression(valeur2ounomSHERB_NOPROGRESSUI).Cettetechniquepermetdecombinerlesdeuxoptionsavecl'opérateurOU(|):
SHERB_NOCONFIRMATION|SHERB_NOPROGRESSUI
Dansl'exemple,nousnedemandonsaucuneoption.Laboîtedeconfirmationapparaîtdonc,seulepreuvequeleprogrammeafonctionné.
FIGURE14.2:ProgrammeimpératifsousWindows
LestypesWindowsEncomplémentsdestypesdeslangagesCetC++,Windowsdéfinittouteunesériedetypesdérivéspour réduire les risquesd'erreur.Laplupartdeces types sontdéfinisdanslefichierd'en-têteWinDef.h.Envoiciunaperçu.
Tableau14.1:TypesdedonnéesnumériquesentiersWindows.
Nom Taille Signéoupas
BYTE 8bits Nonsigné
WORD 16bits Nonsigné
DWORD 32bits Nonsigné
INT32 32bits Signé(UINT32pournonsigné)
INT64 64bits Signé(+varianteU)
LONG 32bits Signé(+varianteU)
LONGLONG 64bits Signé(+varianteU)
OnremarquequelestypesINT32etLONGsontéquivalents.C'estdûàl'histoiredesmicroprocesseurs,passésde16à32puisà64bits.
Types indirects (pointeurs) : comme tous les systèmes à événements et messages,Windows utilise abondamment les pointeurs. Vous les reconnaissez au préfixe P(pointeur)ouLP(pointeurlong).
OuvronslafenêtreAprès ces préliminaires, nous pouvons nous lancer dans une véritable applicationWindowsquevouspourrezmontreravec fiertéàvosamis.Découvronsd'abord lesquatregrandesétapesrequisespourréalisercespectacle.
1. Déclarationdelafenêtreprincipale(parcequevouspourrezen
créerd'autresparlasuite)etinscriptionsystèmepar
RegisterClassEx().
2. Créationeffectivedelafenêtreparlafonction
CreateWindowEx().
3. Entréedanslaboucleprincipaledelafonctionincarnéeparle
blocwhilequisetrouveàlafindelafonctionprincipale.Ilne
doityavoirquelecodedefind'exécutionaprèscetteboucle
caronnesortdelabouclequepourquitterl'application.Cette
bouclescrutelafiled'attentedesmessagesetlestraitel'un
aprèsl'autre.
4. DéfinitiondelafonctionderappelWndProc().C'estcette
fonctionquevousn'appellerezjamaisdansvotreprogramme
(elleestdéclaréeaveclamentionCALLBACK).C'estlenoyau
Windowsquival'appelerpériodiquementquandilyaurades
messagespourvous.
Voyons à quoi ressemble la mise en application (c'est le cas de le dire) de cesprincipes à travers un programme Windows complet. Nous commençons pardécouvrirl'applicationtellequ'elleseprésenteàl'utilisateur.
L'applicationd'exempleLeprojetétantàbutpédagogique,ilconsisteàafficherunefenêtrequivamontrerlescoordonnées du pointeur de souris et celles de la fenêtre. Voici l'aspect del'application.
Cettefenêtreminimaleestdéjàdotéedetoutcequ'unutilisateurd'aujourd'huisupposepouvoirtrouver:
» uncadredefenêtreavecunebarredetitreetunesurfaceutile;
» desboutonsdanslabarredetitre:àdroite,leboutondefermeture
(enhautàdroiteici)etlesboutonsdedépliementetderepliement
auformaticône;àgaucheleboutond'accèsaumenudefenêtre;
» lapossibilitédemodifierlesdimensionsdelafenêtreenagrippant
unbordetdeladéplacerenl'agrippantparlecorpsdelabarrede
titre(endehorsdescasesactivesàdroiteetàgauche).
FIGURE14.3:L'applicationMSF04enaction.
Nousavonsrépété l'affichagedescoordonnéespourqu'ellesrestentvisibles lepluspossible lorsque les dimensions de la fenêtre sont beaucoup réduites. Cescoordonnées sont mises à jour pendant les déplacements de la fenêtre au sein del'écran.
Lesecond jeudecoordonnéesn'est actifque lorsque lepointeur se trouvedans leslimites de la fenêtre. Ces coordonnées souris sont relatives à la fenêtre et non àl'écran. Dans ce projet, nous avons demandé de donner au départ à la fenêtre unelargeur de 450 pixels sur une hauteur de 250 pixels. Sur la figure, le pointeur estpresque dans le coin inférieur droit, aux coordonnées (421, 201). L'origine esttoujoursdansl'anglesupérieurgauche(delafenêtreoudel'écran).
Le nom MSF04 signifie que trois versions plus élémentaires du projet sontdisponiblesdanslesarchivesd'exemplesdulivredisponiblesurlesitedel'éditeur.Laplacemanquedans ce livrepour commenter les trois versionsqui aboutissent àcelle-ci.
Le texte source que nous allons découvrir comporte à peine plus d'une centaine delignes,cequiestpeuquandontientcomptedetoutcequiestdéjàpossible.
EtudedutextesourceUne fois n'est pas coutume, nous allons découvrir le texte source par des capturesécransréaliséesdansl'éditeurdel'outildedéveloppementCode::Blocks(installationexpliquéeenannexe).Pourassurer la lisibilité,nousavons fractionné lecontenuen
trois captures. Commençons par le commencement. Nous ne commentons pas leslignesdontlesensestévidentsil'onalulapartieprécédentedulivre,nicellesdontles commentaires dans le code suffisent ou que nous laissons telles que l'ébauche(stub)lespréinjectequandvousdémarrezunprojetdansl'atelier.
Bienqueletextesourceoccupeenviron110lignes,ilnedéfinitquedeuxfonctions:WinMain()etFoncRapp(),d'environ50ligneschacune.
FIGURE14.4:Partie1/3duprogrammeMS-WindowsMSF04
Lesprédéclarations1/*ProgPLN:WindooMSF04*/
2#include<windows.h>
3#include<stdio.h>
Laligne2demandel'inclusiond'unfichierd'en-têtespécifiqueausystèmeWindows.Ilrassembledesdéclarationsindispensablespourlasuiteetcomportelui-mêmedesdizainesdedemandesd'inclusion.
6LRESULTCALLBACKFoncRapp(HWND,UINT,WPARAM,
LPARAM);
Dansleprototypedefonctionci-dessus,lamentionLRESULTestuntypededonnéespécifique.LequalificateurCALLBACKdésigneunefonctionderappel.Decefait,FoncRapp() est le nom choisi pour la fonction que le système Windows vapériodiquementappeler.Vuducôtéduprogrammeur,c'estunrappel,nonunappel.
NousentronsensuitedanslafonctionWinMain().
WinMain(),étape1préparatoireCettefonctionessentielleetobligatoireremplacelafonctionmain()traditionnelle.Elles'étenddelaligne12àlaligne63.
12intWINAPIWinMain(HINSTANCEmonInsta,
13HINSTANCEhInstaPrec,
14LPSTRlpszArgument,//Optionsdeligne
decmd
15intnCmdShow)//Format
d'ouverture
Lafonctionattendquatreparamètresd'entréequ'elleobtientdusystèmeaudémarrage.Seulelepremiernousimporte.
17HWNDhfen;
HWNDestuntypespécifique(unpointeur)quipermetd'établirunlienavecl'objetenmémoire qui correspond à la fenêtre. Notre fenêtre sera nommée hfen. Leslignes17à33constituentlaphasepréparatoireavantcréationdelafenêtre.
23wincl.lpfnWndProc=FoncRapp;
24wincl.hInstance=monInsta;
25wincl.lpszClassName=szClassName;
Enligne23,nousprécisonslenomquenousavonschoisipourlafonctionderappel.Son corps occupe toute la secondemoitié du texte source.En 24, nous utilisons lavaleur obtenue du système au démarrage et en 25, nous attribuons le nomque nousavionschoisipourlaclasse.
Les lignes 27 à 33 sélectionnent les éléments visuels. Nous conservons les choixstandard.
36if(!RegisterClassEx(&wincl))return0;
Voici la première instruction. L'application ne démarre pas si la fonction appeléerenvoie une valeur nulle. Elle demande l'inscription de l'application en luitransmettantlastructurededonnéesquenousvenonsderemplir.Sinousavonsréussice test, nous pouvons préparer l'appel à la fonction qui va créer la fenêtre enmémoire.
WinMain(),étape2decréationdelafenêtreLa fonction que nous appelons attend pas moins de douze paramètres (lignes 39à51)!Le3eestletitredelafenêtre,les7eet8eprécisentlalargeuretlahauteurinitialesetl'avant-dernierdoitêtrelenomattribuéànotreinstancedefenêtretelquereçudansWinMain().
Saufavariegrave,lafonctionréussitetnousrécupéronsnotrepoignée(«handle»)danslavariablehfenprévueàceteffet.Nousnousenservonspourl'étapeultime.Eneffet,lafenêtreexistebienenmémoire,maisellen'apasétéincrustéesurl'écran,cequenousfaisonsavecShowWindow().
53ShowWindow(hfen,nCmdShow);/*Renduvisuel*/
Nousretransmettonssansytoucherlesecondparamètrereçuaudémarrage.
FIGURE14.5:Partie2/3duprogrammeMS-WindowsMSF04.
WinMain(),étape3deboucleprincipaleLa fin de la fonction principale WinMain() est une boucle dans laquelle votreprogramme reste jusqu'à sa fin d'exécution. Vous n'en sortez que si l'appel renvoiezéro, et il ne renvoie cette valeur que si vous avez par votre fonction de rappeltransmisausystèmelemessagedesortie,messagequelesystèmedéposedanslebacd'arrivée des messages de votre application. Quand ce message est lu parGetMessage(),onsortdelaboucleetonrendlecontrôleausystème.parreturn.
Labouclenefaitquetroisactions:
» lireleprochainmessageenattentedanslafile;
» appelerunefonctiondeconversion(Translate)descodesdetouchesclavierenmessagesplusdigestes;
» retransmettre(Dispatch)lemessageausystèmequivarappeler
votrefameusefonctionderappel.
Aupremiercontact,apprendrequevotrebeauprojetpassesavieàfairetoujourslestroismêmesopérationsestdéroutant.Noussommesàlafindelafonctionprincipaleetnousn'avonsrienvuquipermetted'afficherdescoordonnéesàl'écran!
FoncRapp(),làoùl'onréagitMais la solution est là : tout se passe dans la fonction de rappel, cette étonnantefonctionquevouscréezpourensuitenejamaisl'appeler!
Lalignedetêtedelafonctionderappelmontrequ'ellevarecevoirquatreparamètres.Rappelons (sic) que ce n'est pas vous qui appelez cette fonction,mais le noyau deWindows. Le deuxième paramètre est le message que vous allez scruter dans unestructureswitch. Les deux derniers contiennent par exemple les coordonnées dupointeur.
FIGURE14.6:Partie3/3duprogrammeMS-WindowsMSF04.
66LRESULTCALLBACKFoncRapp(HWNDhfen,UINT
message,
WPARAMwParam,LPARAM
lParam)
{
68HDChDC;
Laligne68sertàdéfiniruncontextegraphique(DeviceContext)quinousserautilepourlesfonctionsd'affichagedetexteoudetracé.
Dela ligne72à la ligne110,noussommesdanslastructuredetestswitchpourtester le message reçu. Dans cet exemple, nous avons choisi de réagir à quatreévénements:
Tableau14.2:Descriptiondesquatremessagesprisencharge.
Ligne Message Description/action
75 WM_RBUTTONDOWN Sileboutondroitestactionné,nous
provoquonsl'affichaged'uneboîtemessage
modale(modalesignifiequevousdevezla
refermerpourpouvoirretrouverl'usagedela
fenêtreprincipale).Elleafficheletextepréparé
enligne69.
79 WM_DESTROY Cemessagefatalpeutavoirétéémispar
l'utilisateurencliquantdanslacasede
fermeture(ouenchoisissantQuitterdansun
menuFichier).Lesystèmevousleretransmet,
maisvouspouvezdésobéirsivousavezune
raisonvalable.Ici,nousémettonslemessage
quivafairesortirvotreprogrammedelaboucle
principaleàlafindeWinMain().
83 WM_MOVE Sil'utilisateuradéplacélafenêtre,nous
récupéronsdansdeuxvariableslesnouvelles
coordonnées,nousréclamonsuncontexte
graphiquepourpouvoirécrire,puisnous
préparonsletextecompletparsprintf()et
l'envoyonsparTextOut().Ilnefautpasoublier
derestituerlecontexteparReleaseDC().
94 WM_MOUSEMOVE Mêmelogiquequepourlecasprécédent,sauf
quenousrécupéronsaussil'étatdestrois
boutonsdesouris.
L'affichage par la ligne 103 de l'état enfoncé ou non du bouton central utilise uneexpressionquiméritequelquesprécisions:
((boutons&MK_MBUTTON)?1:0)
Il s'agitde l'opérateur ternaireduCqui testeuneexpressionetexécutecequ'ilyajuste après le point d'interrogation si l'expression est vraie ou cequ'il y a après lesigne deux points si c'est faux. L'expression combine par un ET logique la valeurbinairereçuedanswparamavecunevaleurconstante(unmasque)quipermetdenetesterquelebitduboutoncentral.S'ilestenfoncé,lerésultatestvrai.
default:/*Onrendlecontrôle*/
returnDefWindowProc(hfen,message,wParam,
lParam);
En lignes 108 et 109, le cas fourre-tout default, habituellement de piètreimportance, devient ici extrêmement sensible.Vous y décidez ce qu'il faut faire detouslesautresévénementsquevousnegérezpasexplicitement(etilyenabeaucoup).
SivousoubliezdepasserlerelaisàlafonctionsystèmeDefWindowProc(),celarevientàdirequepourtouslesautresmessages,ilnefautrienfaire.Etdonc,nefaireaucunedesnombreuses actionsque le système fait àvotreplace commeafficher lafenêtre,dessinerlesboutons,etc.Undétail.
La fonction se termine par un return normal dans les quatre cas gérés, afin d'allerpêcherleprochainmessageenattente.
Sicelavousdit,allezdécouvrirdanslefichierdesexempleslesautresprogrammespourWindowsqueles limitesdepaginationdulivrenepermettentpasdeprésenterici.
Nouvellesapproches
Dans lessystèmesdefenêtrage lesplus récents (parexemple la librairieQT),vousn'accédezentempsnormalpasdirectementà lafiled'attentedesmessagescarvoustravaillezavecdesgestionnairesdédiésauxdifférentsévénementsetdesauditeursquisontprévenusquandunévénementlesconcerne.Maiscettefiled'attenteesttoujoursprésenteetvouspouvezyaccéderpouruncontrôleplusprécis.
Lescomposantsd'interfaceNousn'avonspasprésenté les composantsde l'interfaceutilisateurque l'ondésignesouventpar le terme«widget» (windowgadget).Cesontcesélémentsque tout lemonde connaît : boutons radio, cases à cocher, listes déroulantes, barre demenus,barresd'icônes,etc.
Ces composants qui forment une sorte d'alphabet visuel sont prêts à l'emploi.Vousapprendrezviteàvousenservirenprenantl'habituded'allerlireladocumentationderéférenceenligne.
Pourlescomposantsd'interfaceappeléscontrôles,voyez:
http://msdn.microsoft.com/fr-fr/library/bk77x1wx.aspx
Pourlesmessages,voyez:
http://msdn.microsoft.com/fr-fr/library/e129xdd7.aspx
RécapitulonsCette brève incursion dans la programmation événementielle constitue une étapeintermédiaireavantd'aborderlaprogrammationorientéeobjets.
Nous y avons découvert que le fonctionnement d'une application n'est plus de nosjours ce long chemin solitaire qu'emprunte le flux d'exécution d'un programmetraditionnelenmodetexte.Dorénavant,ilfautsesoucierdesautresprogrammes,cartous les systèmes sont devenus multi-tâches, même sur les telliphones sous iOS,AndroidouTizen.
Avec la programmation objets, l'aspect social descend jusqu'au niveau de vosfonctions qui deviennent des comportements appartenant à des entités distinctes quis'échangentdesmessagestoutaulongdel'exécution.
N
Chapitre15Programmeravecdesobjets
DANSCECHAPITRE:
» L'approcheorientéeobjets
» AperçuenC++etenJava
» Lecercleetl'ellipse
ousavonsvudans le chapitre sur la constructionduprogrammeexécutablequedèsqu'unprojetprenaitunecertaineampleur,ilétaitlogiquededistribuerletextesource dans plusieurs fichiers satellites qui gravitent autour de l'unique fichier
contenantlafonctiondedémarragemain().
Cetteapprochemodulairepermetdéjàderépartirletravailendomaines:unsourcepourledialogueutilisateur,unautrepourstockeretrechargerlesdonnéesdepuisundisque,unautrepourfairetouslescalculsetunsuperviseurquicontrôleetcoordonnelesmodules.
Dans lesgrandsprojets, lapremièreétaped'analysedubesoindoitétablirdefaçontrès détaillée tous les traitements qu'il faudra ensuite exprimer dans l'infolangagechoisi.Celaobligeà faireun trèsgrandécartentre leniveaud'analyseet leniveaucodage.On a donc cherché à permettre au langagedeprogrammationd'exprimer lasolutiondefaçonmoinséloignéedel'analyse.
C'estundesapportsdelaprogrammationorientéeobjets(abrégéeenPOO).Ils'agitdedéfinirdesmini-programmesayantuneexistenceetdescomportementspropres.Unobjet(saclassegénératriceenfait)estconstituédedeuxparties:
» Lapartieinterne(implémentation)enfermepresquetoutesles
fonctionsinternes(baptiséesméthodes)etdonnéesinternes
(baptiséesattributsoupropriétés)quisontenquelquesorte
privatisées.
» Lapartienomméeinterfaceestconstituéedesseulséléments
(méthodesouattributs)accessiblesdel'extérieurdel'objet.
L'approche POO permet de construire l'ossature dynamique du programme endéfinissant des objets de façon proche de la structure logique du problème àautomatiser. Ces objets s'interpellent et collaborent (notion de message). Le fluxd'actionsquienrésulterestebeaucouppluslisiblequedansl'approche«classique»impérativetellequedulangageC.
Justement,commençonsparundernierregardsurcebonvieuxlangageCdontl'étudeconstitueunebasesolidepourcequivasuivre.
Delaquasi-POOenCVous vous souvenez du dernier chapitre de la Partie 3 ? Nous y avons parlé(rapidement)destructuresdedonnées(motcléstruct)etdepointeurs.Unpointeurest une variable dont le contenu est une adresse qui peut être celle de la premièreinstructiond'unefonction.
OnpeutenlangageCdéfinirunestructureregroupantdesvariablessimples,d'autresstructuresetmêmeunpointeursurunefonction,cequipermettradedéclenchercettefonctionencitantlenomdupointeur:
LISTING15.1Textesourcedefuncptr.c
//funcptr.c
#include<stdio.h>
structstrucAutre{
charch;//Pasdevaleurinitialedansunedefde
struct
};
structquasiobj{
intmaVar;
structstrucAutrestI;
int(*ptrF)(int);//Déclaration
pointeur/fonction
};
intmonFP2(inty)
{
printf("DepuismonFP2!%d\n",y);
return(0);
}
intmain()
{
structquasiobjqo;
qo.maVar=999;
qo.stI.ch=65;
printf("%d%c\n",qo.maVar,qo.stI.ch);
qo.ptrF=&monFP2;//Ciblagedelafonction
qo.ptrF(32000);//Appelindirect
return0;
}
Cette façon de regrouper dans unemême entité (une structure) des variables et desconteneurs de fonctions constitue la mécanique fondamentale des langages qui ontsuccédéaulangageC.
Unobjetregroupedesvaleursetdesblocsd'actions.Lesvaleurssontdesvariablesquel'ondésignesouslesnomsdepropriétésoudonnéesmembres.Lesblocsd'actionssontdesméthodes.
Chaque objet constitue unmini-module de traitement de valeurs et de fourniture deservicesqued'autresobjetspeuventsolliciter.CommeunefonctiondulangageC,lescomposants internes de l'objet sont inaccessibles de l'extérieur (sauf ouvertureexplicite).Pourmodifierunedonnéeappartenantàunobjet,ilfautluidemanderdelefaireenluienvoyantunmessage,enfaitenappelantuneméthodedel'objetdéclaréecommeaccessibledel'extérieur.
L'objetincarneunecapsulefonctionnelle.C'estlanotiond'encapsulation.Maisonnepeutpasdéfinirunobjetàpartirderien.Unobjetesttoujoursuneapplicationd'unerecettequiestuneclasse(uneinstancedeclasse).
C'estlaclasse!
Définirunestructure,c'estcréerunnouveautypequiestunmodèlethéorique.Quandcettestructureréunitdesdonnéesetdesfonctions,elleprendlenomdeclasse.
De même qu'on ne peut pas utiliser int comme nom de variable, mais commemodèle de variable, un nomde classe sert à créer un ou plusieurs objets réels quioccuperontdel'espaceenmémoire.
LagrandeidéedelaPOOestqu'elleinviteleprogrammeuràadopterdeuxnouveauxpointsdevuesursonprojet:leniveaudesclassesetleniveaudesmultiplesobjetsdontildemandelacréationàpartirdesclasses.
Une classe peut être définie à partir d'une autre classe. Elle devient héritière desdonnéesetméthodesdesamère.Toutunensemblederèglespermettentd'établiretdecontrôlerainsidevéritableslignéesgénéalogiques.
Le raisonnement suit un parcours du générique au spécifique. Chaque générationsuccessive depuis une classe ancestrale ajoute des particularités, c'est-à-dire denouvellesdonnéesetméthodes.
Définir les contours des classes consiste à chercher ce qu'un groupe d'élémentsfonctionnelsonttousencommun.
Onpeut envisagerune classeVehiculequi est lamère des sous-classesVelo,Voiture,Camion,Avion,Bateau,etc.Lasous-classeVoitureseralamèredes sous-classesBerline,Urbaine,Cabriolet, etc. La relation est de styleEST:unCabrioletESTuneVoiture;uneVoitureESTunVehicule.
[modeaccès]classnomclasse{
//Déclarationsd'attributs
//Déclarationsdeméthodes
};
LaclasseVehiculenedéfinitquelefaitqu'ils'agitd'unobjetmatérielpouvantsedéplaceretemporterdeschosesvivantesou inertesavec lui.Lesspécialisationssedéduisentlogiquement.
Chaqueclassedéterminelesautorisationsd'accèsàsesmembresavecdesmotscléstelsquepublic,privateetprotected.
Une classe peut donner libre accès à certaines parties (en abuser fait perdre toutl'intérêt de cette approche). Elle peut réserver l'accès aux seuls objets de sadescendance (de ses sous-classes). C'est le mode protected. Elle peut mêmeinterdire tout accès à certaines parties (données ou méthodes) même à sesdescendantes (modeprivate).En revanche, les objets créés à partir d'unemêmeclasseontunaccèstotalauxcontenuslesunsdesautres.
Uneclassepeutmêmeêtredéclaréeabstraite:danscecas,vousnepouvezpascréerd'objet àpartirdecetteclasse.Ellenepeut servirquedemodèlepourdesclassesplus spécifiques. Imaginez une classe Mot dont dériveront les sous-classesSubstantif, Verbe, Adjectif, etc. Un mot est toujours qualifiable. Vousn'écrivezjamaisdemots;vousécrivezdesnoms,desverbesetdesadjectifs.Maisleconceptdemotlesenglobetous.
Lesobjets:unvastesujetLetermeconsacré«objet»peutdérouteraupremiercontactpuisqu'ils'agitdepetitsensembleautonomes,alorsqu'unobjetestausenscourantquelquechosedepassif,àladifférenced'unsujet.
Puisqu'unobjetvaexisterdanslamémoiredel'ordinateur,celasupposedeprévoirunmécanismepourluiréserverdel'espaceetpourrestituercetespacelorsquel'objetn'aplusaucunlienactifavecleresteduprogramme.
Pourconstruireunobjetàpartirdelarecettequ'estlaclassechoisie,ondéfinituneméthodespécialenomméeconstructeur.Cetteméthodedoitporterlenomdel'objet.De même, pour libérer la mémoire, on peut définir un destructeur, mais certainslangagesfontleménageautomatiquement(Java).
SpécialisationUnobjetpossèdetouteslesdonnéesetméthodesdéfiniesparsaclasseettoutescellesdontcetteclassehéritedesonascendance.
Partonsduconceptdepoint.OnpeutdéfinirparuneclasseGeoPointunpointsurunelignedroite.Commedonnéemembre,nousnouscontentonsdesapositionsurlaligne.Commeméthode,nouspouvonspartirducoupledeméthodesAvancer()etReculer()quimodifientsapositiond'unequantitéfixe(translation).
NouspouvonsensuitecréeruneclassedérivéeGP2Dquivaserviràcréerunpointsur une surface, donc en deux dimensions. Elle hérite dePosition et des deuxméthodes.Pourgéreretdéplacerunpoint surunesurface, il fautdeuxcoordonnées(enxeteny).Laclassedérivéevadoncdéfinirunesecondecoordonnée(pourlesensy) et redéfinir lesméthodeshéritées, sans changer leurnom, cequi vamasquer lesversionsoriginales.
Dans la figure suivante, nous utilisons la convention UML pour schématiser lescontenusetlesrelationsentreclasses.
FIGURE15.1:Relationsentreclasses.
Demême,onpeutdériverunesous-classeGP3Dquiajoute la troisièmedimensionpourrepositionnerunpointdansl'espace.
Grâceàunmécanismeautomatiqueprévuparlelangage,sivousdemandezàunobjetdefairequelquechosequin'estpasdéfinidanssaclassegénératrice,lahiérarchiedesesclassesancestralesestscrutéeenremontantjusqu'àtrouvercelledanslaquellelaméthodeaétédéfinie.
HéritageoucompositionDanslapratique, l'héritagen'estpas lasolutionunique.Certains langagescommeleC++ proposent l'héritage multiple : une classe dérive simultanément de plus d'uneclassemère.Mais cela peut amener au problème du losange de lamort (diamondproblem)silesdeuxclassesmèresdériventd'unegrand-mèreunique.
D'autres techniques sont apparues et notamment la composition qui consiste àincorporeruneclassedansladéfinitiond'uneautre.Larelationchange:
Héritage : ClasseFille EST (cas particulier de) ClasseMère ;
Composition : ClasseComposée A (comportements de)
ClasseComposante.
Selonvous,qu'est-cequ'uneautomobile?
AutomobileESTChâssis_roulantAVECENPLUSMoteur
oubien
AutomobileESTMoteurAVECENPLUSChâssis_roulant
ouencore
Le concept d'auto-mobile est la composition de deux concepts, auto
(doncmoteur)etmobile(doncchâssisroulant).
Aviez-vousprévuqueprogrammerunordinateurvousamèneraitàcegenrededébat?
Surcharge(overloading)Voussavezqu'unefonctiondulangageCdoitêtredéclaréeavecunprototypequicitel'essentiel(lavaleurrenvoyée,sonnometsesparamètres).Ceprototypeconstituesasignature,unesorted'interface.
Il est possible de définir plusieurs fois lamêmeméthode à condition que quelquechosepermettededistinguerlesvariantes:soit le typederetour,soit lenombredeparamètres d'entrée, soit leur type. Par exemple, l'opérateur + du C est déjàpolymorphe : il permetd'additionnerdeuxentiersintou deux flottantsdouble.Vousdevinezque les instructionsmachinenesontpas lesmêmespuisque la largeur(lenombred'octets)àcopierestdifférente.
Leprincipedesurcharge(overloading)permetauprogrammeurdeprofiterdecettepossibilitédanssesprojets.Biensûr,c'estàmanieravecprécautions,puisquevouspouvez rendre le résultat illisible.Rien ne vous empêche de surcharger l'opérateurd'addition+pourunnouveau type (unestructurenecontenantqu'unentier),maisendécidant que dans ce contexte, l'opérateur divise son premier opérande par sonsecond,cequivadéroutertoutlemonde.Restonssérieux.Surcharger,c'estadapteruncomportementexistantàunnouveautypequ'ilneconnaîtpasencore.
Redéfinition(overriding)Un objet doit souvent spécialiser le comportement dont il hérite. La méthodeReplacerAZero() qu'il faudrait définir pour la classe GP2D contiendra plusd'instructionsquelaméthodedemêmesignaturequ'elleareçuedesonancêtre.
Redéfinir (override) une méthode est accepté, et constitue même le principe dumécanisme de polymorphisme : une action identique va déclencher une réactiondifférenteselonlanatureexactedel'objetverslequellemessageestenvoyé.
Ilnefautpasconfondreredéfinitionetsurcharge.
En relisant laphraseprécédente, l'auteur constatequ'il ne fautpas allerplus avant.LesconceptsdelaPOOsontpeunombreux,maisleursrépercussionssontimmenses.La pratique et l'étude sont indispensables pour acquérir la façon de penserappropriée. Nous sommes toujours dans un livre de présentation générale de laprogrammation.
DUS.O.L.I.D.
S comme Seul responsable : chaque objet couvre ni trop, ni trop peu de
surface fonctionnelle. Un léger changement dans le projet n'éclabousse pas
desdizainesd'endroits.
OcommeOuvertà l'enrichissement,maisferméàlaretouche.Unbonobjet
sertdesourced'inspirationpourdesobjets futurssansdevoirêtreremisen
cause.
LcommeLignage(ouLiskov,nomdeladamequiaproposél'idée)pourque
lesdescendantsn'oublientpasleursancêtresetrestentcompatiblesaveceux.
I comme Interfaces spécifiques, à privilégier plutôt qu'une interface trop
polyvalente.
DcommeDépendancedesabstractions,pasdesspécialisations.
LeslangagesC++etJavaCette description-éclair des principes de la POO vous laisse deviner qu'il y avraimentunsautqualitatifdans la façondepenser lesprogrammespar rapportà la
programmationclassique,structurée/impérative.
Passons à unebrèvedécouvertede l'aspect d'un texte sourcedans chacundesdeuxlangagesorientésobjetslesplusutilisés:leC++etJava.
Conçuvers1990parBjarneStroustrup,lelangageC++estl'héritierdulangageC.Ilaéténormalisé.SaplusrécenteversionestC++11.LamiseàjourC++17devraitenfinincorporerlecodageUTF-8pourlaplusgrandejoiedesprogrammeursqui«ontdel'accent».
L'autre langage objet majeur est le Java. Créé en 1995 par le constructeurd'ordinateurs scientifiques Sun, il se distingue résolument du C++ sous plusieursaspects:
» Javaestsemi-interprété:lacompilationduprogrammegénèreun
ouplusieursfichiersdansunlangageintermédiairenommé
bytecodequidoitêtretraduitàlavoléeparunexécuteur(RuntimeMachine).Celapermetauxprogrammesdefonctionnersans
retouchesurtoutemachinepourlaquelleilexisteunexécuteur.
C'estleconceptdeportabilité.
» Javaesttotalementorientéobjets:toutestclasseouutilisationde
classe,doncobjet(sauflestypessimplespournepasgreverles
performances).
» JavaestassezfacileàapprendrepourceuxquiconnaissentleCou
leC++.
» Javaaétéadoptéàvasteéchelledanslemondedesentrepriseset
disposedecefaitd'uneénormebasedecoderéutilisable.
UnexempleenC++LelecteurquiauraassimilélapartieprécédenteconsacréeauxfondamentauxenCneserapasdépayséàlalecturedel'exemplesuivant.
LISTING15.2Exempleheritage.cpp
//heritage.cpp
#include<iostream>
usingnamespacestd;
//Classedebase
classGeoForme{
public:
voiddefinirLargeur(intw){
iLargeur=w;
}
voiddefinirHauteur(inth){
iHauteur=h;
}
protected:
intiLargeur;
intiHauteur;
};//Nepasoublierle;
//Classedérivée
classRectangle:publicGeoForme{
public:
intlireSurface(){
return(iLargeur*iHauteur);
}
};//Nepasoublierle;
intmain(void)
{
RectangleRect;
Rect.definirLargeur(5);
Rect.definirHauteur(7);
//Calculeretafficherlasurface
cout<<"SurfacedeRectangle:"<<
Rect.lireSurface();
cout<<endl;
return0;
}
Nousdéfinissonsd'aborduneclassedebasenomméeGeoForme.Dans l'exemple,nousnecréonsaucunobjetàpartird'elle.Nousaurionsmêmepularendreabstraiteen lui incorporant aumoins une fonction sans corps, uniquement constituée de sonprototype(unefonctionvirtuelle).
Laclassedéfinitdeuxméthodesd'accèsenécriture(definirXXX)quiconstituentlemoyenpréconisédemodifierlesvaleursdesdeuxdonnéesmembresiLargeuretiHauteur,carellessontprotégéesparunedéclarationprotected.Petitdétail:notezlaprésencedusignepoint-virguleenfinducorpsdeclasse.
Decetteclasse,nousdérivonsuneclasseplusspécifique,Rectangle.Ellenefaitqu'ajouteruneméthodedecalculdesurfaceàtoutcequ'elleareçuenhéritage.
Nousarrivonsensuitedanslatraditionnellefonctionmain().Ellen'estpasdansuneclasse,àladifférencedeJavapourquimêmemain()doitêtreuneméthodedelaclassemajeure(celledontlenomcorrespondàceluidufichierdelaclasse).
Dans main(), nous créons un objet d'après la classe Rectangle puis nousappelonsdeuxméthodespourdéfinirsesdimensions.Vousremarquezquecesappelsn'ontpasdecibledanscetteclasse.Cettesituationestprévue:toutelahiérarchieestscrutéeàpartirdelaclassecourantejusqu'àtrouveruneclassequidéfinitlaméthodeappelée.Enfait,cesontlesméthodesdeGeoFormequisontexécutées.
Nousdécouvronspourfinirlanouvellemanièredefaireafficherdesvaleurs.EnC++,lesentrées/sortiessonttoutesdetypeflux.Lafameusefonctionprintf()duClaisselaplaceàdesséquencesbaséessurcoutetsurl'opérateur<<.
cout<<"SurfaceRectangle:"<<Rect.lireSurface();
Dans ladernière instructiond'affichage,nousappelons laméthode localede l'objetRectquirenvoielasurfacecalculée.
LeprocessusdeconstructiondeC++IlestquasimentlemêmequeceluiduC.Danslecasdelasuited'outilslibresGNU,ilfaut appeler le compilateurg++ au lieu degcc. Certains fichiers d'en-tête ont unelettrecajoutéeaudébutdunomdefichierconnuenC.
UnexempleenJavaCeciestnotrepremiercontactaveclelangageJava.LesdifférencesavecleC++nesontpastroublantes.Lesprincipalessontquelesdirectivesd'inclusionn'ontplusdepréfixe # et que la fonction main() est enchâssée dans la classe majeureEmplois.
LISTING15.3ExempleEmplois.java
//Emplois.java
importjava.io.*;
classEmploye{
StringsNom;
intiAge;
StringsPoste;
doubledSalBrut;
publicEmploye(Stringnom){//Constructeur
this.sNom=nom;
}
publicvoidempAge(intage){//Accesseurpour
iAge
iAge=age;
}
publicvoidempPoste(Stringposte){//Accesseur
sPoste=poste;
}
publicvoidempdSalBrut(doublesal){//Accesseur
dSalBrut=sal;
}
publicvoidprintEmploye(){//Afficheur
System.out.println("Nom:"+sNom);
System.out.println("Age:"+iAge);
System.out.println("Poste:"+sPoste);
System.out.println("Salairebrut:"+
dSalBrut);
System.out.println("---------");
}
}//Pasde;enJava!
publicclassEmplois{
publicstaticvoidmain(Stringargs[]){
//Instanciationdedeuxobjets
Employeemp_1=newEmploye("JeanEymard");
Employeemp_2;
emp_2=newEmploye("PetulaVoulutu-Lahu");
emp_1.empAge(56);
emp_1.empPoste("Chefdeprojet");
emp_1.empdSalBrut(1000);
emp_1.printEmploye();
emp_2.empAge(41);
emp_2.empPoste("Ingenieurlogiciel");
emp_2.empdSalBrut(38000);
emp_2.printEmploye();
}
}
Nous commençons par la définition de la classe Employe qui déclare quatredonnéesmembrespuisunepremièreméthodeportant sonnom.C'est le constructeurd'objet.Laméthodeestappeléeaumomentoùvouscréezunobjetdecetteclasse.Ici,le constructeur se contente de donner une valeur initiale à un seul de ses quatrechamps(donnéesmembres).
Noustrouvonsensuitetroisméthodespourmodifierlesvaleursdesautreschamps.Cesontdesaccesseurs.
Accesseurestunanglicismepourdécrireunetechniquededélégationpourintervenirlàoùl'onn'estpasautoriséàagirdirectement.
Ladéfinitiondelaclassesetermineavecuneméthoded'affichage.
Nousarrivonsalorsdansunesecondeclassequiestlamajeurepuisqu'ellecontientlaméthode main(). Nous créons un premier employé emp_1 en combinant deuxétapes qui sont décomposées pour le second employé. La création est effective auretourdel'appelvianewauconstructeurdelaclasse,laméthodeEmploye().
Leresteestuneséried'affectationdevaleursauxchampsdesobjetsetd'affichage.
Lefichiersourcedoitporterlemêmenomquelaclassemajeure,etrespecterlacasse.Ici, laclassesenommeEmplois, avecunecapitale.Pourcompiler leprogrammesurlignedecommande,onécrira:
javacEmplois.java
Lerésultatestunouplusieursfichiersàextension.class.Cenesontpasdesfichiersexécutablesautonomes.
LamachinevirtuelleJava(JVM)Lorsque vous utilisez le compilateur Java, le résultat est un fichier qui n'est pasdirectementexécutable.Ilestconstituédepseudo-code(bytecode).C'estunesortedecode presque du niveau des instructions en assembleur, mais il reste suffisammentgénériquepourquelatraductionentempsréelverslecoderéelsoitassezrapide.Cebytecode comprend les mêmes familles d'instructions que l'assembleur : desinstructionsdechargementetstockagedevaleurs,d'autrespourlagestiondelapiled'appels,lesopérationsarithmétiques(ADD,SUB,MUL,DIV,etc.),lesbranchementsetlessautsconditionnels(environ150pseudo-instructions).
Pourexécuteruneclasse,vousindiquezlenomdufichierdelaclassemajeuresansmentionnerl'extension.class:
javaEmplois
LamachineJVMvalirelespseudo-instructionsetalimenterlamachinematérielleenvéritables instructions appropriées à son modèle de processeur. Voici le résultataffichépournotreexempleminimal.
Nom:JeanEymard
Age:56
Poste:Chefdeprojet
Salairebrut:1000.0
---------
Nom:PetulaVoulutu-Lahu
Age:41
Poste:Ingenieurlogiciel
Salairebrut:38000.0
---------
Fichiersarchives.jarLelangageJavaproposederegrouperdansunfichieruniquesousformecompresséetous les fichiersdesclassesd'unprojet.Dansnotreexemple, la lignedecommandeestlasuivante:
jarcvfeEmplois.jarEmploisEmpl*.class
Le troisièmeparamètrede la commande jarest le nomde la classemajeure.C'estindispensablepourque l'exécuteursacheoùtrouver lafonctionmain().Lefichier.jarrésultantcontienttouteslesclassesspécifiéesenfindeligne.Pourl'exécuter:
java-jarEmplois.jar
Exceptionsetgestiond'erreursJava(leC++également)permetdedélimiterdansunblocaveclemotclétryuneouplusieursinstructionsquipourraientrencontrerunsoucipendantl'exécution.Siunproblème survient avec l'une de ces instructions, une exception est déclenchée etl'exécutionestsuspendue.Soitvouslagérezlocalementenprévoyantunbloccatch,soitvouslalaissezremontertoutelaséquencedesappelsd'objetsjusqu'àmain(),etaupirejusqu'àl'exécuteurJVM.
Vouspouvezmêmeprévoirunblocfinallydontlecontenuseraexécutédanstouslescasd'exception.Uncourtexemple:
LISTING15.4ExempleTrycatch.java
//trycatch.java
importjava.util.*;
publicclassTrycatch{
staticinti,j;
publicstaticvoidmain(String[]args){
System.out.println("Lancement:");
System.out.println(newDate());
inta=1,b=0;
try{
System.out.println(a/b);
}
catch(ArithmeticExceptione){
System.out.println("Bouh,ontentedediviserpar
0?");
}
finally{
System.out.println("Noussommesdansfinally!");
}
System.out.println(newDate());
}
}
RéutilisationdecodeetAPILa promesse demeilleur recyclage du code existant dans les nouveaux projets estsatisfaite par le simple fait que l'architecture de classes vous oblige à définir desentitéslogiquesquinesontpaspolluéesparlesdétailsderéalisation.
Une classe bien définie est facile à repérer comme composant réutilisable dans unautreprojet.Sesdétailsinternespeuventêtrepeaufinésalorsqu'elleestdéjàutiliséeenexploitation.
L'ensembledespartiespubliquesd'ungroupedeclasses (leurs interfaces) constitueunesortedepointdeconnexionentreuneoffredeservices(lesclasses)etunbesoinde services (votre projet). Le résultat est proche de la liste des prototypes d'unelibrairiedefonctions(ondisait«bibliothèque»)quiconstituel'essentield'uneAPI(ApplicationProgrammingInterface).
Maisqu'est-cequ'uneclassebiendéfinie?
CodeetlinguistiqueLa programmation objets n'est pas qu'une nouvelle approche pour écrire desprogrammes. Les discussions qu'elle suscite se tiennent à un niveau beaucoup plusproche des préoccupations de sémantique des linguistes et de la compréhension dufonctionnementducerveaudesneuro-physiciens.
Enguised'exempletrèssimple(enapparence),supposezquenousvoulionspréparerla création d'un programme de dessin. Le graphiste utilisateur doit pouvoirsélectionnerunoutildetracéparmiplusieurs.Nousprévoyonsdedéfinirdesclassespourlesobjetsdetracé,doncpourdesobjetsCercleetdesobjetsEllipse.
La question est : si nous optons pour une classe Cercle et une autre classeEllipse, laquelle doit être la classe mère de l'autre (si nous choisissonsl'héritage)?Est-cequ'uncercleestuneellipseoul'inverse?
» Solution1:Uncercleestuncasparticulierd'ellipsedontlegrandet
lepetitaxeontlamêmelongueur.C'estuneellipsethéorique
(certainsdisentmêmedégénérée).
» Solution2:Uneellipseestuneapplicationimparfaiteduconcept
essentiel(platonique)decercle.LaclasseCerclesedéfinitparune
seulepropriété(donnéemembre):sonrayon,alorsquel'ellipsea
besoind'yajouterunsecondaxeetuneorientation(angledugrand
axe).
Ledomainedelagestionn'estpasàl'abridecesdébatsstratosphériques:vousdevezinformatiserlafacturationd'unassureur.LaclasseFacturedoit-elledériverd'uneclasse PreuveLegale au même titre que Contrat ou d'une classeInfoSortantequienglobe toutes lesdonnéesquisontgénéréespar l'entrepriseversl'extérieur?
Vousconviendrezquecegenrede réflexionnesesituevraimentplusauniveaudesadressesmémoireetautrestestsdevaleursnumériquesbinaires.
SwingPuisquenousavonseffleuréJava,rappelonsquecelangagedisposed'unelibrairiedeclassespourconstruireuneinterfaceutilisateurd'applicationpilotéeparévénements(fenêtresetsouris).SonnomestSwing.Nousfournissonsquelquesexemplesdansle
fichier archive qui accompagne ce livre (site de l'éditeur). Voici un aperçu d'uneapplicationJava/Swing:
FIGURE15.2:Vuegénéraled'uneapplicationSwing(SwingMenu).
RécapitulonsLaprogrammationorientéeobjetsmodifielesproportionsentreletempsàconsacreràl'analysedubesoinetletempsàprévoirpourrédigerlecodedelasolution.Ellevadanslesensdel'histoirehumaineetduprogrèstechniquepuisquelesconnaissancess'ajoutentetformentlaculture.
Dans le prochain chapitre, nous revenons à un sujet beaucoup plus pragmatique etcontemporain : les langages descripteurs qui ajoutent de l'intelligence aux données.LesmotsmagiquesvontêtreSGML,HTML,XMLetCSS.
ORDREETVOLUPTÉ…
Alors que l'Univers refroidit inéluctablement (le désordre appelé entropie
augmente), l'humain procède d'unmouvement inverse : il augmente l'ordre
deschosesencomprenantdeplusenpluscommenttoutcelafonctionne.
A
Chapitre16LangagesWebcôtéclient
DANSCECHAPITRE
» IlétaitunefoisleSGML
» Debalisesetdestyles:HTMLetCSS
» Moteur,action:JavaScript
veccechapitre,nousentronsdansunvastemondedontchacundenouspossèdeunecertaineexpérience,carraresdenosjourssontceuxquin'ont jamaisvuunepageWebsurunécran.Envingtans,Internetabouleversélessociétéshumaines
enutilisantl'informatiquepourdiffuserdel'information(cequin'étaitaudépartqu'unréseaud'échangesentremilitairesetscientifiques).
Malgré son nom français, l'informatique n'automatise pas encore aisémentl'informationtellequenousl'entendons:desélémentsporteursdesenstransmissiblesd'unepersonneàuneautre.
Vousm'avezremarqué?"Moiaussi,regardez-moi!"
(Je suis une autre phrase et je confirme que la précédente vous a demandé de laregarderpourcequ'elleest.)
Regardez le titre et la première phrase ci-dessus sans les lire, comme des objets.Essayezdefairedesallers-retoursentrepercevoirdestracésetressentirlesensdesmotssurgirdansvotreesprit.Puispoursuivez.
DonnéeetinformationDèslesannées1960,notammentchezIBM,leschercheurssesontrenduscomptequedesmassesexponentiellesdedonnéesallaientêtregénérées,transmises,modifiéesetstockéespardesordinateurs.
Pourlesvaleursnumériques,aucunsouci.Unordinateur«sait»quelavaleur3estplus petite que la valeur 4, cette vérité étant même gravée dans le silicium (nousavonsdécouvertlesporteslogiquesdanslaPartie2).
Enrevanche,pourlestextesdenoslangages,ilyaunabîmeentrel'ordinateuretnous,abîme qu'ont commencé à combler des solutions logicielles (reconnaissance decaractères,de laparole, traductionassistée).Lesordinateursactuelsneconnaissentquedesdonnées,làoùnouslisonsdesinformations.Essayezdelirecequisuit:
kadrfguijrtukkkzeegduujnxioosoijjksihs
Cen'estplusde l'information.Etencore, l'humainestprogrammépourchercherunesignification dans tout ce qu'il perçoit. Pour la machine, cette ligne n'est pas plusincompréhensiblequeduFlaubert.Ilfautdoncl'aiderenajoutantdescommentaires.
Depuis des siècles des spécialistes dans les maisons d'édition appliquent desconventionsd'annotationenajoutantdesmentionsenmargedesmanuscritspourquelestypographessachentquoicomposerentitre,ensous-titre,ennotedebasdepage,etc.Cemarquagedutexteadonnénaissanceauconceptdelangagedemarquageoudebalisage(MarkupLanguage).
Quandunrédacteurdécidedemettreunmotengras,c'estquecemotdoitselon luiaccrocherleregard,commeunecélébritéparmilafoule.L'intentiondel'auteurestdefairecomprendreaulecteurquecemotestplusimportantquelesautres.Demêmelestitresserventàclarifierlalecture.
Pourappliquerdestraitementsautomatiquesàuntexte,ilfautajouterdesexplicationsdestinées à l'ordinateur pour qu'il puisse travailler « comme s'il comprenait » lecontenu.C'est lebutd'un langagedemarquage.Marquer,c'estposerunrepèrepourreconnaître un endroit. On parle aussi de balise. Ici, les choses que l'on veutdistinguer, ce sont des mots ou groupes de mots. On pourra ainsi marquerdifféremmentunedatedenaissance,unedatedebatailleetunedatedecréationd'unesymphonie.
L'ancêtreestparminous:le<SGML>Le langage HTML dont nous allons parler est un rejeton d'un langage bien moinsconnu. Le SGML a été créé vers 1974 pour répondre aux besoins des grandesadministrations et des militaires américains qui étaient à l'époque les seulsorganismes pouvant acquérir un ordinateur. Et ces établissements avaient déjàd'énormes volumes d'informations candidates à des traitements et stockagesautomatisés.
SGMLestunacronymesignifiantStandardGeneralizedMarkupLanguage:langagedebalisagegénéralistestandardisé.Sonobjectifestdedécrirelesdonnéesauniveau
deleursignification(leursémantique).Voiciquatrelignesdetexte:
TestdeSGML
Jesuisdutexte.
Jesuisunenotedepied.
Cedocumentapourtitre"TestdeSGML".
EtvoicilerésultatunefoiscetexteannotéenSGML:
<!doctypedocsystem"testsgml.dtd">
<!--Commentaire-->
<doc>
<titre>TestdeSGML
</titre>
<para>
Jesuisdutexte.
<notepied>Jesuisunenotedepied.</notepied>
</para>
<para>
Ce<emphase>document</emphase>apourtitre
“<citetype=article>Testde
SGML</cite>”.
</para>
</doc>
Ilyadequois'yperdre!Oùestletexteutile?C'estsimple:engrasentrelechevronfermantd'unebaliseetlechevronouvrantdelaprochainebalise.
Levrainomdecequiestentrechevronsest«élément».Unélémentpeutavoirdesattributs.Labalise<cite>aunattributtypedontlavaleurestarticle.
Dans cet exemple, les noms des éléments ont été librement choisis. L'élément<titre> aurait pu s'appeler <tagada> ou plus simplement <t>. Le SGMLpermet à chacun de définir son jeu de balises. Cette définition est décrite dans undocument compagnon, la Définition de Type de Document ou DTD (l'exemple enspécifieuneenpremièreligne).
Semettred'accord:lesDTD
Créer ses balises personnelles perd tout intérêt quand il s'agit de communiquer lesdonnées à d'autres personnes. C'est pourquoi des groupes se sont formés dans lesdifférents secteurs (armée, banques, recherche, industrie, aviation, santé, etc.) pourconstituerensembledesDTDcouvrant tous lesbesoinsenfonctionde lanaturedesinformations à gérer (documentation technique, pièces de rechange, transactions,rapportsderecherche,etc.)
LaDTD présente chaque élément avec ses règles d'apparition (obligatoire ou non,uniqueoumultiple,combiend'attributs,dequeltype,etc.).
Lesconventionsprincipalessontcelles-ci:
» Lesbalisesdansledocumenttextedoiventêtrehiérarchiséeset
appariées;dansl'exempleprécédent,labalise<doc>entroisième
ligneestappariéeàlabalise</doc>endernièreligne.
» Deuxbalisesdifférentesnesechevauchentpas;lapremièredoit
sefermeravantd'enouvriruneautre,saufsil'autreserefermeà
l'intérieurdelapremière(voir<notepied>dans<para>ou
<emphase>danslesecond<para>).
» Certainscaractèresdoiventêtreneutraliséspourqu'ilsne
provoquentpasuneffetsurletraitement(commeenlangageC).
C'estainsilecasdesguillemetsanglaisdel'exemple,quisontcodés
chacunsurseptcaractèrescommençantparlesigne&etse
terminantparunpoint-virgule.Leguillemetouvrantestcodé
“(LeftDoubleQUOtation).
La rigueurdubalisagen'estpasvaine :desoutilspermettentdeconfronterun textebalisé à laDTD à laquelle il prétend se conformer, ce qui s'appelle lavalidation.L'intérêtestquelesprogrammeursquivoudrontensuiteécriredesprogrammespourexploiterlecontenudufichiernerencontrerontpasdesoucis.
Deplus,numériserdestextesenlesannotantpermetdelesstockerdansdesformatsouverts et pérennes, ce qui garantit que l'information enchâssée à l'intérieur seratoujoursaccessible.Lesdonnéesne sontpasdépendantesdebrevetsoude la santéfinancièred'uneentrepriseprivée.
LelangageSGMLreste trèsutilisé,mais iladonnénaissanceen1998àunlangageétendu, le XML (le X pour eXtensible) qui a des objectifs plus ambitieux encore.MaispassonsdirectementaupetitfrèreHTML.
LeHTML:unSGMLpourtousContrôler l'apparence ou la présentation d'un texte est un besoin aussi ancien quel'écriture.Pensezauxenluminuresmédiévales.Dufaitqueleschercheursproduisentbeaucoup de textes scientifiques et qu'ils ont très tôt disposé d'ordinateurs, ils ontinventé des langages de mise en page capables notamment de coder des formulesmathématiquesetchimiques.LeplusconnudeceslangagesdeprésentationsenommeTeX(prononcerTekh).
Le créateur duWeb, Tim Berners-Lee, travaillait au CERN de Genève quand il arendu public en 1991 sa première version de HTML, un sous-ensemble du SGMLdéfinissant une poignée de balises. Il a également écrit le logiciel du navigateurcapabledecomprendrecesbalisesetlelogicielduserveurquitransmettaitlespagesdemandéesgrâceauprotocoleHTTP.
LeHTMLestlafusiondedeuxtechniques:
» Leconceptd'hypertexte:unmotdutexteapparaîtsoulignépour
indiquerqu'enactivantcemot(àlasourisouauclavier),cela
déclencheunerequêteàuneadresseIP(InternetProtocol)quiestmasquéederrièrecemot.Cetteadressehébergeunserveurqui
répondenrenvoyantlecontenudelapagedemandée.
» Unlangagedeprésentation:quasimenttouteslesbalisesduHTML
contrôlentlastructurevisuelledesinformationsaveccomme
objectifhabitueldefournirl'équivalentd'unepagedelivre.
L'énormedifférence entreHTMLetXMLestque leHTML imposeunensembledebalises dont les noms doivent être reconnus par tous les logiciels navigateurs dumonde(sansdevoiranalyserunfichierDTDassocié).
PourdécouvrirlaprogrammationCeluiquiveutapprendreàcréersapremièrepageWebpeutpicorerparmilesbalisesdéfiniesdanslestandardHTML.Nousenverronsquelques-unes.
LeHTMLesttrèstolérant,alorsqueleXMLnel'estpasdutout.Lerendud'unfichierHTML est le résultat du travail d'un moteur de rendu (d'affichage) qui constituel'essentiel du logiciel du navigateur Web (Firefox, Internet Explorer, Safari). Cemoteurfaitcequ'ilpeutpourinterpréterlesbalises.Siunebaliseestorpheline(pasde balise fermante), il tente d'afficher le texte le mieux possible, au pire sansenrichissementvisuel.
LesmilliardsdepagesWebaccessiblesdepuisvotresalonsontautantd'exemplesquevouspouvezétudier.VouspouvezscrutertoutlecodeHTML,lesrèglesdestylesCSSet même le code source des portions en JavaScript ! LeWeb est open-source parprincipe.
UneossatureàremplirUnfichierHTMLdoitseconformeràunestructureminimalequiestunearborescence.Ellecorrespondàl'arbreDOM(DocumentObjectModel):
<!DOCTYPEhtml>
<html>
<head>
<metacharset="UTF-8">
</head>
<body>
</body>
</html>
Lesretraitsmontrentlesniveauxdecettearborescence.Labaliseprincipale<html>englobe toutes les autres à l'exception de la déclaration de type en ligne 1. Ellecontientdeuxparties:latête<head>quinecontientrienquipuisseapparaîtredansla page (seulement le titre d'onglet) et le corps <body>. Dans l'exemple, nousajoutonsunedirectivepourpréciserquenousutilisonslejeudecaractèresUTF-8,cequirendlecontenucompatibleavectouslesalphabetsetidéogrammesexistants.
Pourcréeroumodifierun fichierdansce format, il fautpenseràchoisirUTF-8aumoment de l'enregistrer. SousWindows dans leBloc-notes, choisissezUTF-8 dansl'optionEncodagede la boîte Enregistrer sous. Sous MacOS dans TextEdit,vérifiezl'optionEncodagedanslasecondepagedesPréférences.
Cetteossatureaccueilleletexteàafficher:
LISTING16.1Textesourceh_simple.html
<!DOCTYPEhtml>
<html>
<head>
<metacharset="UTF-8">
<title>TestHTML(h_simple.html)</title>
</head>
<body>
<h1>Susausoulignement!</h1>
<p>Le<u>soulignement</u>estunepratiqueà
bannir.</p>
<p>Eneffet,c'estlaconventionutiliséesurle
Webpour
désignerles<ahref=h_cible.html>liens
hypertextes</a>.
</p>
<p>Onavaitprisl'habituded'ajouterdestraits
de
soulignementsurlesmachinesàécrirepour
simulerla
<b>miseengras</b>desimprimeurs.
</p>
</body>
</html>
Danscetexemple,nousavonsvolontairementajoutédesespacesenpleinmilieudesphrasesducontenupourquevouspuissiezbienvoirl'arborescence.Voyeznotammentlalignecommençantpar«désignerles».Cesespacesnesontpasmaintenuspar lemoteur de renduHTMLqui n'en conservequ'un seul.Même le saut de ligneaprès«leWebpour»estphagocyté.Onnerevientàlalignequ'aprèslabalisefermante</p>.Vousleverrezdanslaprochainefigure.
FIGURE16.1:Rendudel'exempleh_simple.htmldansunnavigateur.
Contrairementàuntextesourcedelangagedeprogrammation,lecodeHTMLn'apasbesoin d'être converti. Il est directement utilisable par un navigateur Web qui vainterpréter le contenu ligne après ligne. Voici l'exemple précédent ouvert dansFireFox.
CertainsprogrammeursprofitentdufaitqueleHTMLn'obligepasàrefermerlabaliselapluscourante,<p>avecunebalise</p>.C'estpourtantunehabitudeàprendreenvuedepasserauXMLquinefaitpascetteconcession.
L'aspect de la page est le résultat des choix faits par le logiciel navigateur. Pourchaquebalise,desparamètressontenvigueurpourlenomdelapolicedecaractères,lacouleurdutexte,l'alignement,laprésenced'uncadre,lesmargesentreparagraphes,etc.
Vouspouvezalleràl'encontredeces«réglagesusine»endéfinissantdesstyles(unpeucommelesfeuillesdestyleWordouOpenOfficequetroppeudegensexploitent).CettepersonnalisationutiliseunlangageassociéauHTML:lelangageCSS.
L'habitetlemoine(CSS)CSS signifieCascading Styles Sheets parce que vous pouvez appliquer plusieursdéfinitionsdestylesencascadeàunmêmeélément.Leprincipeestdesélectionnerdu
contenu en fonction de la balise qui le contient.Vous pouvez cibler par le nom debalise oubienpar deux attributs : unnomde classe (ce qui suitclass=dans labalise)ouunidentifiantunique(cequisuitid=danslabalise).
Vous pouvez définir un style directement dans le fichier HTML dans un bloc<style></style>,maisunfichierexterneestpluspratiqueetpeutêtreappliquéà tous les fichiersd'un sitepourgarantirunaspecthomogène. Il suffitd'ajouterunebalisedelienexterne:
<linkrel="stylesheet"href="fichier_styles.css">
Voicidesvariationsd'aspectrésultantdeplusieursdéfinitionsdestyles:
FIGURE16.2:Rendudel'exempleh_css.htmldansunnavigateur.
Voiciletextesourcedufichierprincipaldecontenu:
LISTING16.2Textesourceh_css.html
<!DOCTYPEhtml>
<html>
<head>
<metacharset="UTF-8">
<title>TestHTML(h_css.html)</title>
<linkrel="stylesheet"href="h_styles.css">
</head>
<body>
<h1>Untitreenpolicesans-serif(bâton)</h1>
<pclass=intro>Cetexteestrendudanslafenêtre
sous
l'emprised'unfichierCSS.</p>
<p>VoicilecontenudufichierCSS:</p>
<pid=code>
<!--LignesCSSeffacéespournepasperturberla
lecture.-->
</p>
</body>
</html>
Nousavonsvolontairementeffacéleslignesducontenudelabalise<pid=code>,carceslignessesituentdansunautrefichier.
Labalise<link>estdotéededeuxattributs.C'estvousquidécidezdelavaleurdusecondenindiquantlenomdufichierdestylesàutiliser.Voicisoncodesource.Lasyntaxe n'est pas très éloignée de celle des langages C, C++ et Java (blocs entreaccolades,points-virgules):
LISTING16.3Textesourceh_styles.css
h1{
color:blue;
font-family:Helvetica,Geneva,Arial,sans-serif;
}
p{
font-size:120%;
}
.intro{
color:red;
}
#code{
font-size:80%;
color:green;
}
Ce fichier CSS contient quatre règles de style. Les trois modes de ciblage sontutilisés:d'abordparlenomdebalise(pourh1etpourp),puisparlenomdeclasse(avec.intro) et enfin par identifiant (avec #code). Comparez les valeurs desattributsdanslefichierHTMLetleurutilisationdanslefichierCSS.
Ilyatroisparagraphesdecontenustandardàbalise<p>.Voicicommentfonctionnelemécanismededéfinitionencascade:
» Lepremierparagraphedetexteestviséavecunnomdeclasse,ce
quilefaitapparaîtreenrouge.
» Maisc'estd'abordunebalise<p>,cequiexpliquequecommele
secondparagraphe,ilsoitaffichédansunepolicede120%par
rapportàlataillenormale.
» Letroisièmeparagrapheestviséparlarègled'identifiant,cequifait
afficherleslignesdecodedansunepolicepluspetiteetenvert.
Toute règle qui n'est pas redéfinie reste en vigueur pour les éléments qu'elle vise.Plusieurs éléments peuvent être baptisés avec le même nom de classe, maisl'identifiantestprévupourresterunique.
Cemoded'accèsà l'apparencedescontenusn'estpas seulementexploitablepar lescréateurs de pagesweb (lesweb-designers,métier très demandé de nos jours). Larigueur de la structure duHTML permet à un programme d'aller analyser (certainsdisent « parser » ) un fichier HTML pour le modifier : rajouter ou échanger desbalises,modifierlecontenu,créeruneautrepageparextraction,etc.
Vous disposezmêmed'un vrai langage de traitement, disponible dès le départ dansn'importequelnavigateur:c'estleJavaScriptouECMAScript.
Naviguerenplongée
Pour la plupart des gens, le navigateur est une application simple : une barred'adresse, quelques boutons pour avancer et reculer et une grande surface pourafficherlapageWeb.
Mais votre navigateur dispose d'une panoplie complète d'outils pour enquêter etintervenirsurlescoulissesdelapage.Nousavionssoulevéuncoinduvoiledanslepremierchapitredulivre.
Un seul geste suffit à accéder aux rouages internes de la pageWeb. La commanded'affichagedupanneauDéveloppement.
Pourouvrirlepanneaudedéveloppement:
» DansFirefox:menuOutilspuisDéveloppementWebpuis
Inspecteur.
» DansSafari:menuDéveloppementpuisAfficherl'inspecteur
web.Pourrendrecemenuvisible,vousdevrezéventuellement
accéderauxPréférencesdeSafari,puisàlapageAvancées.Tout
enbas,voustrouverezlacasedel'optionAfficherlemenu
Développementdanslabarredemenus.
VouspouvezaussiinstallerlemodulecomplémentaireFirebug.
(Sinécessaire,cliquezdansl'ongletdupanneauInspecteur.)
En déplaçant le pointeur de souris parmi le code source dans le panneau del'inspecteur,vouspouvezvoirdanslapageréelleàquoicorrespondchaqueélément.Danslafigureprécédente,levoletdroitmontrelesrèglesCSSenvigueur.
Parmi les autres panneaux, notez celui intituléDébogueur. Il donne directementaccèsaucodesourcedesscriptsprésentssurlapage(nousajoutonsunscriptunpeuplusloin).
FIGURE16.3:Analysedesélémentsdeh_simple.html.
UnesélectiondebalisesHTMLAvant dedécouvrir comment intervenir sur le contenu et la structure en JavaScript,voiciunesélectiondesbalisesHTMLlesplusutilisées.
Tableau16.1:SélectiondebalisesHTML.
Balise Description
<a> Lienhypertexte
<area> Zoned'uneimagemosaïqueinteractive
<audio> Documentsonore
<b> Texteengras
<br> Sautdeligne
<button> Boutonactivable
<canvas> Surfacedetracégraphique
<caption> Titredetableau
<col> Propriétédecolonnedetableaudans<colgroup>
<colgroup> Groupedecolonnesdansuntableau
<dialog> Fenêtreouboîtededialogue
<div> Sectiondedocumentdeniveaubloc
<dl> Listededescription
<dt> Entréedelistededescription
<em> Textemisenavant
<figcaption> Titrede<figure>
<figure> Conteneurpourregroupertitreet<img>
<footer> Pieddedocumentoudesection
<form> Formulairedesaisie
<h1>à<h6> Niveauxdetitres
<head> Descriptiondudocumentnonaffichée
<i> Miseenitaliques
<iframe> Cadrepourinjecteruneautrepage(<frame>et<frameset>ne
sontplussupportésparlaversionHTML5)
<img> Insertiond'uneimage
<input> Composantdesaisie
<label> Labelàassocieràunélément<input>
<li> Elémentdeliste
<link> Lienavecuneressourceexternetellequ'unfichierCSS
<menu> Menudecommandes
<menuitem> Elémentdemenu
<nav> Liensdenavigation
<ol> Listenumérotée(ordonnée)
<option> Optiondelistedéroulante
<script> Zoned'insertiond'instructionsdescript
<section> Sectiondudocument
<select> Listedéroulante
<span> Sectiondudocumentdeniveauligne.
<strong> Passageimportant(engénéralgras)
<style> Blocdestyles
<table> Tableau
<td> Celluleuniquedetableau
<textarea> Zonedesaisiemultiligne
<th> Celluled'en-têtedetableau(header)
<tr> Lignedetableau(row)
<ul> Blocd'unelisteàpuces
Moteur,Action:JavaScriptLanormeHTMLprévoitunebalisepour toutcequin'estpasduHTML : labalise<script>. Vous pouvez y insérer des lignes écrites en langage JavaScript pourajouterdescapacitésd'interactiondelapageWebavecl'utilisateuretpouranimerlapage,ensommelarendreinteractiveetplusattrayante.
JavaScriptn'aaucunrapportdirectavecJava,maissasyntaxes'inspirebeaucoupdeJavaetduC++,commevousallezlevoir.
LISTING16.4Textesourceh_testJS.html
<!DOCTYPEhtml>
<html>
<head>
<metacharset="UTF-8">
<title>TestHTML+JavaScript(h_testJS.html)</title>
</head>
<body>
<style>
#GT{color:blue;font-family:sans-serif;font-
size:150%;}
#cible2{color:green;}
</style>
<h1id="GT">TestdeJavaScript(h1avecid=GT)</h1>
<pid="cible1">Petittexteavecid=cible1.</p>
<pid="cible2">Petittexteavecid=cible2.</p>
<buttononclick="traduire()">Traduire!</button>
<script>
varobj;
obj=document.getElementById("cible1");
obj.innerHTML="Bienlebonjour(jeviens
d'arriver).";
functiontraduire(){
vartitre=document.getElementById("GT");
titre.innerHTML="WirkönnenJavaScripttesten
!";
}
</script>
</body>
</html>
Enfin, nous retrouvons le genre de prose qu'affectionnent les programmeurs : desdéclarationsdefonctionsetdevariables,desaffectations,desparamètresd'appel,deschaîneslittéralesentreguillemets,bref,cequenousavonsprisletempsdemaîtriserdanslaPartie3.
Et au niveau du langage HTML, nous avons aussi fait un sérieux bond en avant :regardezlalignesuivante:
<buttononclick="traduire()">Traduire!</button>
FIGURE16.4:Aspectdeh_testJS.html.
Avec labalise<button>, leHTML sort de son rôle de simple présentateur. Sonattribut onclick est un nom d'événement. Si l'utilisateur clique le bouton, celadéclencheunappelàlafonctionJavaScriptspécifiée.
Sivous testezcetexempleetvoyezapparaîtreundrôlede losangeà fondnoirà laplaceduotrémadanslenouveautitre,c'estquevousn'avezpasenregistrélefichieravec le codage UTF-8 ou choisi un autre encodage dans le navigateur(Présentation/Encodage du texte dans Safari,Affichage/Encodage decaractèresdansFirefox).
FIGURE16.5:Résultatsilefichiern'estpasauformatUTF-8.
Lebloc de la balise<script>contient trois instructions qui sont exécutées dèschargement de la page et une définition de fonction qui, elle, ne sera exécutée quesuiteàl'appelvialebouton.Voyezcommeonprocèdepourrécupérerunaccèsàunélémentdel'arborescenceavecdocument.getElementById(),cequipermetd'allerécrireunnouveaucontenu.
Voiciunautreexemplequiprouvequ'avecJavaScriptunesimplepageHTMLinertepeutdeveniruneapplication.Nousyaffichonsunehorlogequipeutêtreremiseàzéroavecunbouton.
FIGURE16.6:Vuedurendudeh_horloge.html.
Nous découvrons quelques nouveautés dans la partieHTML : le choix d'un fichierimagecommefonddefenêtrecommeattributdelabalise<body>etl'utilisationde
stylesCSSexternespourembellirleboutonavecgestiondusurvolduboutonvialarègled'événement#btnRAZ:hover(danslefichierCSS).Amenezlepointeursurleboutonsanscliquerpourvoirl'effet.
LISTING16.5Textesourceh_horloge.html
<!DOCTYPEhtml>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;
charset=UTF-8"/>
<title>Exempleh_horloge.html</title>
<linkrel="stylesheet"href="h_horloge.css">
</head>
<bodybackground="papier.gif">
<h1>UnehorlogeenJavaScript
</h1>
<p></p>
<formname="horloform"class="heure">
Observonsletempspasser…
<inputtype="text"name="affhor">
<br/><br/>
<buttononclick="effacer()"id="btnRAZ">Remiseà
zéro</button>
</form>
<scripttype="text/javascript">
functionhorloger(){
varnow=newDate();
varh=now.getHours();
varm=now.getMinutes();
vars=now.getSeconds();
if(h<10)h="0"+h;
if(m<10)m="0"+m;
if(s<10)s="0"+s;
vartimix=h+"h"+m+"m"+s+"s";
document.horloform.affhor.value=timix;
setTimeout("horloger()",1);
}
alert("Démarrageouredémarrage!");
document.horloform.affhor.value="999999";
varvalt=document.horloform.affhor.value;
if(valt=="999999"){
alert("Valeurreluedanslechamptexte!")
horloger();
}
functioneffacer(){
document.horloform.affhor.value="999999"
}
</script>
</body>
</html>
L'essentieldutravailsetrouvedanslafonctionhorloger()quicréeunobjetdeclasseDate() afin de récupérer périodiquement l'heure système et la mettre enformepourl'injecterdanslazonedesaisie/affichage.Leboutondéclenchelafonctioneffacer()quiinjecteunevaleurconvenuedanslechampafindefaireréussirletestaveclavariablevaltet relancer la fonction. (Leprojetpourraitêtreécritdefaçonplusoptimale,maismoinspédagogique.)
HTML5etlesextensionsJSLaversion4dataitde1998,et laversion5vientdeparaîtreen2014.Cetempsdematuration vous laisse deviner l'importance des nouveautés, surtout au niveau del'interactivité. Il devientpossibledeprogrammerdes jeux interactifsuniquement en
HTML5.De très nombreuses extensions JavaScript sont disponibles.Envoici troistrèsutilisées:
» jQuery:PouraccélérerlacréationavecJavaScriptdetoutcequia
traitauxformulaires.
» D3.js:Pourvisualiserdesdonnéesgraphiquement.
» DataTables:Pourgérerfacilementl'accèsàdesbasesdedonnées.
EtPHP?Dans les blocs <script>, vous pouvez rencontrer des lignes faisant référence à unfichieràextension.php.Ils'agitdeprogrammessituéssurleserveurWeb.Aulieudedemanderauserveurd'envoyer tellequelleunepageHTML,vous faitesdéclencherl'exécutiond'unfichierdecodePHP,généralemententransmettantdesparamètresenfin d'adresse (méthode GET). Ce programme va générer une page HTML et larenvoyeràvotrenavigateur.
Nousn'aborderonspaslaprogrammationcôtéserveurici.
VLesdixcommandements
DANSCETTEPARTIE:
Dixpistespourpoursuivreladécouverte
Dixerreursdeprogrammationfréquentes
U
Chapitre17Dixpistesàexplorer
DANSCECHAPITRE:
» LemondedulibreetduWeb
» Autreslangages,autrestechniques
ne foisquevous avez assurédespointsd'ancrage solidesdansundes langagesincontournablesetobtenuunaperçudestechniquesmodernesquisefondentsurleC,c'estàvousdechoisirparmiuneconstellationdepossibles.
LemondedulogiciellibreUnefoisquevousavezapprisàlireduC,vouspouvezvousplongerdanslesmillionsde lignes de code accessibles gratuitement. Choisissez en fonction de votre centred'intérêt :vousvoulez savoircomment fonctionneunesuitebureautique?Procurez-vous le code source de LibreOffice. Connaître les algorithmes de compression dedonnées ? Récupérez la source de 7Zip. Apprendre à gérer des objets graphiquesvectoriels?Inspirez-vousducodesourcedeInkscape.
Des milliers de programmes sont proposés avec le code source sur des sitesspécifiquesappelésréférentiels. Ilssont tousprotégésparunelicencedetypeGPL.Vousêtesautoriséàdupliquerlesprogrammes,àlesmodifieretvouspouvezmêmerejoindrel'équipequifaitvivrechacund'eux.
Unsitefrançaisàrecommander:www.framasoft.net.
AutreslangagesUn bon programmeur doit connaître plus d'un langage. LeCmène naturellement auC++etàJava,maisd'autresapprochestrèsdifférentesméritentd'êtreétudiées.
PythonCréé en 1990 par un Hollandais, Python propose une fusion entre plusieursapproches : celle impérative du C, l'orientation objets de Java et une pincée deprogrammation fonctionnelle à la Lisp. Python a connu en 2008 une mise à jourPython3noncompatibleavecPython2.Voiciunaperçudesasyntaxe:
defbienvenue(nom):
print'Bonjour',nom
bienvenue('Gaston')
LagrandeparticularitédePythonestquec'estlenombred'indentationsquidéterminecequifaitpartieducorpsd'unefonction.Lesaccoladesnesontpasnécessaires,nilepoint-virguledefind'instruction.Unespacedemoinsdansuneligneducorpsd'unefonction,etlaligneestconsidéréecommeextérieureàcecorps.
ScalaLe langage Scala de l'École Polytechnique de Lausanne permet d'aborder laprogrammationfonctionnellequiestassezdifférentedelaprogrammationimpérative.Parexemple,ladistinctionentrefonctionsetvariablesyestremiseencause.
objectBienvenue{
defmain(args:Array[String]){
println("Bonjourlesamis!")
}
}
LesprogrammeursexclusifsMS-WindowssontnombreuxàutiliserlelangageC#,undescendantdeC++prochedeJava.
SQLSQLestunlangagespécialiséquetoutprogrammeurrencontredèsqu'ildoitgérerdesgrandsvolumesdedonnées.C'estunlangagedecréationetd'utilisationdebasesdedonnées relationnelles. Voici un très court exemple de création d'une table puisd'extractiondevaleurs:
CREATETABLEmaTable(
PrixINTEGER,
ArticleVARCHAR(30),
PRIMARYKEY(Prix,Article)
);
SELECTPrix,ArticleFROMMaTableORDERBYArticle;
Pourconstruirecorrectementlastructured'unebase(nombredetablesetqualitédeschamps de chaque table), il faut prévoir un travail de normalisation préalable quipassepardesformesnormalessuccessives(1re,2e,3e,etc.).Lebutdecettephasedeconception est d'optimiser le stockage des données en évitant notamment lesduplications.
DéveloppementWebPHPPourledéveloppementWeb,enplusdeJavaScript,lelangagePHPestincontournablepour les traitements du côté du serveur. Conçu en 1995 par le Canadien RasmusLerdorfpourgérersesproprespagesWeb,ils'estpropagésurleWebaupointd'êtredisponiblesurtouslesserveursWeb.CommeJavaScript,c'estunlangageinterprété(pas de compilation). Une utilisation de PHP consiste à l'incorporer dans du texteHTML,commelesscriptsJavaScriptenutilisantuncouplespécialdebalises<?phppourouvriret?>pourclorelasectionPHP:
<!DOCTYPEhtml>
<html>
<body>
<?php
echo"PetitmessagedePHP!";
?>
</body>
</html>
UnprogrammePHPpeutégalementconstituerunfichierautonomedontl'exécutionestdéclenchéeparunerequêteprovenantd'unnavigateur.
JavaScriptcôtéserveur(node.js)
Une technologie assez récente (2009) consiste à permettre d'utiliser le langageJavaScriptnonplusseulementducôtédunavigateurduvisiteur,maisaussiducôtéduserveur, làoùlePHPrégnaitenmaître.Node.js fonctionneprincipalementdefaçonasynchrone(pasuniquement),c'est-à-direquelademandereçueduclientneprovoquepassamiseenattente.Unefonctionderappelestfourniedanslademande;c'estcettefonctionquiserarappeléeparnode.jsquandletraitementseraachevé.
LLVM,emscriptenetasm.jsDes chercheurs de l'université de l'Illinois ont créé en l'an 2000 le compilateurLLVM. Il part de textes sources en C et C++ pour produire un code nomméreprésentation intermédiaire (IR) indépendantdu typedeprocesseur, exécutableparunemachinevirtuelle(unpeucommelaJVMdeJava).Lecodegénéréestunesortedecodeassembleurextrêmementoptimisé,surtoutauniveaudestypesdedonnées.DenombreuxautreslangagessontdorénavantcompilablesavecLLVM.
Dansunnavigateur,lecodeJavaScriptestinterprété.IlestdecinqàvingtfoispluslentqueducodeCouC++compiléclassiquement(codenatif).L'existencedeLLVMadonnéune idéeàquelquesexpertsquiontconçuunrecompilateurdecodesourcenomméEmscripten.Cetoutil transforme lecodeproduitparLLVMencodesourceJavaScriptoptimisé(plustellementlisible,maistrèsrapide).
Le code produit par Emscripten devient exploitable avec le sous-ensemble deJavaScript nommé asm.js (apparu en 2013) afin d'offrir dans un navigateur unerapiditéd'exécutionprochedecelledesprogrammesnatifsenCouC++.
Pour juger du résultat, cherchez par exemple "bananabread js". LesmeilleuresperformancesrequièrentlenavigateurFirefoxdansuneversionrécente.
Développementsgraphiques(OpenGL)Quasiment tous les ordinateurs et appareils assimilés d'aujourd'hui disposent decapacités de traitement géométrique pour réaliser des affichages graphiques en 2Det3D.Cestraitementssontparexempledescalculsmatricielsdevolumes,d'ombresetdetexturesdessurfaces.
Ces traitements sont pris en charge par un coprocesseur dédié, le coprocesseurgraphiqueouGPU(GraphicProcessingUnit).Surlesmachinesd'entréedegamme,leGPUestintégréauprocesseurcentral,cequilimitelesperformancesparrapportàunGPUentourédesamémoiredédiéesurunecartegraphique.
Pour exploiter ces capacités, vosprogrammeseffectuentdes appels àdes fonctionsd'une librairie graphique selon les conventions d'une interface API. Les deuxlibrairieslesplusutiliséessontOpenGLetDirect3D.
La librairieDirect 3D appartient à la société Microsoft. Elle est utilisée par lesystèmeWindowsetlesconsolesdejeuXBox.
OpenGLestunstandardouvertsupportéparquasimenttouslesfabricantsdematérielvidéo et d'ordinateurs. Les rendus graphiques dans les navigateurs peuvent êtreréalisésavecWebGL,undescendantdeOpenGL.
VisualisationdedonnéesDe nos jours, les énormes volumes de données qui s'accumulent dans tous lesdomainesréclamentdesmoyensnouveauxpourenexploiterlepotentiel(vagueduBigData). Pour ce qui concerne la visualisation dans les navigateurs Web, plusieurslibrairiesdefonctionssontapparues.Nousciteronsd3.jsetp5.js.
d3.jsd3.js est une librairie JavaScript.LamentionD3 signifieData-DrivenDocuments,c'est-à-dire Documents Déduits des Données. Les données d'entrée sont en généralpréparéesdansleformatdefichierJSON.Lesgraphiquessontinteractifs.Voyezdesexemplessurd3js.org.
processing.jsCréé au départ en Java par une équipe de passionnés des arts visuels et donc dugraphismeetdel'audio,lelangagedecréationProcessingaétéportéversJavaScriptcequipermetd'utilisercelangageaveclesextensionscréativesdeProcessing.C'estleprojetp5.js.Denombreuxexemplessontproposéssurlapagesuivante:
https://processing.org/examples/
Arduino/RaspBerryPietlarobotiqueDepuisquelquesannées,leprixdescircuitsintégrésnommésSoC(SystemonaChip)abaisséaupointqu'ilestdevenupossibledeproduiredesnano-ordinateurssurunesurfacedel'ordred'unecartedebancaire.Vouspouvezainsivousdoterpourenvirontrenteeurosd'unsystèmecompletavecdécompresseurvidéofonctionnantsousLinux,Lacommunauté laplusactivedanscesecteurestcelleduRaspBerryPi,uncircuitanglaispouvantservirdemachinededéveloppementcommedecentremultimédiadesalon(ilafaitl'objetd'untitredanslacollectionPourlesnuls).
FIGURE17.1:Lenano-ordinateurRaspberryPi.
Cegenredecircuitestdotédesortiesnumériquespourcontrôlerdespériphériquesdetyperobotiqueouinstrumentation.Lesnano-ordinateurssontdecefaitappréciésdesélectroniciens pour créer de nouveaux montages, notamment en robotique et endomotique.
Unchampderechercheconnexeappeléàungrandsuccèsestceluidesexprimantesouimprimantes3Dquipermettentdeproduiredesobjetsdefaçonadditive.
Réseauxdeneuronesetautomatescellulaires
Ils'agitd'uneapprochetoutàfaitdifférentedesautomatesprésentésdanslaPartieII,puisqu'unréseauneuronals'inspire(sanslecopier)surlemodedefonctionnementdesneurones. Les réseaux de neurones offrent un support aux travaux du domaine del'intelligenceartificielleetdesstratégiesd'apprentissage.
LesautomatescellulairesetConway
LeJeude lavie (GameofLife) est l'archétypedes automates cellulaires.CrééparJohnConway en 1970, il s'agit d'un scénario autonome d'évolution dans une grilled'unecoloniedecellules.Laprogressionseterminesoitparl'extinctiondelacolonie,soitpar lepiégeagedesderniers survivantsdansdes figuresoscillantes.Les règlessonttrèssimples:
Naissance :Unecasevidedonneranaissanceàunebactérieà l'étapesuivantesi lacaseestentouréeparexactementtroisbactéries.
Décès/survie :Labactériemeurtà l'étapesuivantesielleétouffedufaitqu'elleestentouréedeplusde troisbactériesou si elle angoisseparcequ'ellen'aplusqu'unevoisineouaucune.Autrementdit,ellesurvivrasielleadeuxoutroisvoisines.
Uneversiontrèscomplèteetpolyvalentedecegenred'automatesetrouvesurlapagehttp://fiatlux.loria.fr/.
LesdronesautonomesapprenantsUne équipe de chercheurs de l'université ETH de Zurich travaille sur des enginsvolants (des quadricoptères) capables d'apprendre et donc d'améliorer leursperformances.Vouspouvezvisionnerlavidéoréaliséelorsd'uneconférenceTEDparRaffaeloD'Andrea(voyezsurlesiteflyingmachinearena.org).
AlgorithmesQu'est-cequ'unalgorithme?C'estunprocédéintellectuelpourtrouverlasolutiond'unproblèmeàcoupsûretdefaçonconstante.
On envisage de mettre ce concept au programme (sic) des collèges de France.Pourquoiattendreladernièrepartiedulivrepourdécouvrirceconcept?Parcequ'ilestàgéométrievariable.
Ausenslarge,unalgorithmeestunjeuderèglesquidécrituneséquenced'opérationspourpasserd'unétatinitialàunétatfinaldésiré.Manger,marcher,respirermême,ilyaunalgorithmederrièrechaqueactionque l'onoptimiseparcequ'elle sera répétée.Danscesens,toutprogrammeestunalgorithme.
Au sens commun, l'algorithme est une martingale : une technique infaillible pourréussir.Unerecettedecuisineestunalgorithme,unepartitionmusicaleaussi.
Au sens strict, un algorithme est la meilleure solution actuellement connue pourrésoudreunproblèmenotammentnumériqueenexprimantlatactiquedansunlangageindépendantdetoutlangageinformatique.
Voiciquelquesdomainesprincipauxdanslesquelslesalgorithmessonttrèsusités:
» mathématiques:l'algorithmed'Euclidepourtrouverleplusgrand
commundiviseur(PGCD)dedeuxnombresoulafonctionfactorielle
(!);
» trisetrecherchededonnées:trirapide,arbresbinaires,etc.;
» compression/décompressiondedonnées:sansperteouavec
perte,trèsutiliséepourlestransfertsdedonnéesaudioetvidéo
(MP3,JPEG).
» topologie:recherchedupluscourtchemin,calculdetrajectoires
pourrobots,etc.
Le mot algorithme est l'œuvre d'un traducteur de l'arabe vers le latin. Lemathématicien persan Al-Khwarizmi avait écrit un livre sur le calcul d'après lestravauxdel'IndienBrahmagupta.Letraducteureuropéenatraduitletitredulivre,ycompris la première ligne qui portait le nom de l'auteur du livre, ce qui a donné«Algoritmi de numero Indorum » . Et du fait que la partie « -rithme » avait unerésonancearithmétique,etquelecontenuprésentaitdestechniquespourtrouverunesolutionàunproblème,algorithmeestresté.
L
Chapitre18DixerreursfréquentesenC
DANSCECHAPITRE:
» Bourdesfacileàintercepter
» Oublisdivers(point-virgule,break)
» Confusions
es erreurs de programmation se répartissent en deux catégories primaires :Catégorie1:erreursquel'analyseurdetextesourcesaitdétecter,soitenrefusantd'allerauboutduprocessus,soitenémettantunavertissement.
Catégorie2:erreursditesdelogiquequel'analyseuraccepteparcequ'ilnepeutpasvérifierquecequevousavezécritestfautif.
Les erreurs de catégorie 1 sont peu coûteuses puisqu'elles peuvent être très vitecorrigées.Celasupposenéanmoinsquevousdemandiezàl'analyseurdesemontrerleplusstrictpossible(optiondecompilation-Wall).
Voici dix erreurs parmi les plus fréquentes.Certaines ne sont pas réservées qu'auxdébutants.
Bouclevideparpoint-virgulesuperfluC'estuneerreurde logiqueque le compilateurnepeutpasdétecter.Elle consisteàrefermer le bloc conditionnel d'une boucle par un point-virgule isolé. L'erreur estdifficile à trouverparceque cepoint-virgulene se remarquepas.Voici uneboucleinfiniedanslaquellelavariableneserajamaisdécrémentée:
intmaVar=12;
while(maVar>0);
maVar--;
En règle générale, pas de point-virgule s'il y a une accolade ouvrante derrière.Demême,l'oublid'unpoint-virguleenfind'instructionfaitvraimentperdrelespédalesaucompilateur,commel'oublidefermeturepar*/d'uncommentairemultilignes.
OublidebreakdansswitchLastructureconditionnelleswitchduCnegèrepasunblocparcas,maisenchaînetouteslesinstructionsdèsqu'uncasestpositif.
intmaVar=1;
switch(maVar){
case1:
printf("Jetravaille\n");
case7:
printf("Jemerepose\n");
default:
printf("Jenesaisplus\n");
}
Cetexempleaffiche«Jetravaille»puis«Jemerepose».Ilfautajouterunbreak;avantlalignedusecondcas.
Confusionde=etde==Pourcomparerdeuxvaleurs,l'opérateurestledoublesigneégal.Lesigneégalsimpleest l'opérateur d'affectation qui copie la valeur située en membre droit dansl'emplacementmémoire indiquéenmembregauche.Cetexempleafficheunmessageerronécommequoixseraitégalà1:
intx=8;
if(x=1)printf("xvaut1\n");
Uneastucepourévitercesbourdesconsisteàinverserlesdeuxmembres(if(1=x)).Lecompilateurdeviendracapablededétecterl'erreurparcequ'ilestimpossiblede stocker unevaleur dansunevaleur littérale, car ce n'est pas un emplacement enmémoire.
Non-gestiondurestedesdivisionsentreentiers
Sivousindiquezdesvaleursnumériqueslittéralesentières(doncsanspointdécimal),lecompilateurconsidèrequecesontdesentiers:
floatquartDeLitre=1/4;
Dans cet exemple, la variablemémorise la valeur 0 et non la valeur 0.25 espérée.Vousforcezletranstypageavantladivisionsoitenajoutantdequoitransformerundeslittérauxenrationnel(1.0),soit,pourunevariable,enpréfixantavecletypedésiré:
floatquartDeLitre=(float)intA/intB;
Débordementd'unindicedetableauEn C, comme dans beaucoup d'autres langages, le premier élément d'un tableaucorrespondàl'indice0,pasàl'indice1.
Commeconditiondesortied'uneboucle,appliqueztoujoursl'opérateur<à l'indicesivouslecomparezaunombred'éléments:
inti,tab[10];
while(i<10){tab[i]=i+64;i++;}
OublideprototypeLeprototyped'unefonctionsertàlapré-déclarerafinquel'analyseurpuissevérifierque les appels qu'il va rencontrer avant la définition de la fonction sont corrects.Lorsqueleprototypeestoubliéouplacéaprèslepremierappel,l'analyseurappliquedeschoixpardéfaut.Letypederetourseraint,cequiserabiensûrinacceptablesiletypevraimentrenvoyéestdifférent.
floatsalaire=augmenter(2);
L'appelci-dessusseradéfectueuxsansprototypepuisquel'analyseurvasupposerquela fonctionaugmenter() (définie de typefloat,mais plus bas dans le texte)renvoieunevaleurint.Ilvaajouteruntranstypageversletypefloatalorsquelavariableestdéjàdecetype.Lavaleurstockéedanssalaireserafausse.
Danslemêmedomaine,assurez-vousderespecterlestypesdeparamètresdansvosappels.Sivousappelezavecunentierunefonctionquiattendunpointeur,vousallezau-devantdegrossesdifficultés.
Confusionentrecaractèresettableauxchaînes
NousavonsvudansleChapitres7et10queletypenommécharn'estqu'unentiertrèscourt(unoctet).C'estlehasarddel'origineanglaisedulangagequiaintroduituneconfusion avec les caractères que lisent nos yeux humains. L'exemple suivantfonctionne:
//intchar.c
#include<stdio.h>
intmain()
{
unsignedcharmontre=65;
shortsMontre='B';
intiMontre='C';
printf("\nchar='%c'%d",montre,montre);
printf("\nshort='%c'%d",sMontre,sMontre);
printf("\nint='%c'%d\n",iMontre,iMontre);
return0;
}
Voicicequeleprogrammeaffiche:
char='A'65
short='B'66
int='C'67
Vous voyez que l'on peut afficher un caractère en stockant sa valeur dans un typeshortouint.Cen'estqu'auniveaudelafonctionprintf()qu'ilyatentatived'afficherundessindelettresousl'effetde%c.
Unechaînedecaractèresn'estqu'uneséquencedevaleurs(normalementchar,maispasenUTF-8)stockéedansuntableau.
Oubliduzéroterminaldanslestableauxchaînes
En langage C, une chaîne est supposée se terminer par un caractère de valeurnumériquezéro('\0'),c'est-à-direunzéroterminal(ZT).Sicemarqueurn'estpasprésent,denombreusesfonctionscontinuentàprogresserenmémoirejusqu'àtomberparhasardsurunecasemémoirecontenantcettevaleur.C'estextrêmementdangereux.Quandvousdéclarezunechaîneavecunevaleurlittéraleinitiale,l'analyseurajouteceZTpourvous.
Laplupartdes fonctions standardduCpourgérerdeschaînesajoutentunZT,maispastoutesetnotammentpaslafonctiond'extractiondesous-chaînestrncpy()quirenvoiencaractèresmaisn'ajoutepasleZT.Méfiez-vous.
Par ailleurs, pour éviter d'oublier qu'il faut réserver une position de tableau pourstocker le zéro terminal de fin de chaîne, nous vous conseillons de déclarer vostableauxchaînesaveccettenotation:
charmaChaine[20+1];
Erreursdescanf()Lafonctionstandarddelecturededonnéesperturbelesprogrammeursparcequ'ilfautluifournirl'adressedelavariabledanslaquelleelledoitdéposercequ'elleacapté.Il faut doncutiliser l'opérateur d'adresse&en préfixe du nom de variable, sauf sic'estuntableauchaîne,puisqu'untableausansindiceincarnedéjàuneadresse!
scanf("%d",&monEntier);//Préfixe&
obligatoire!
scanf("%30s",monTabloChaine);//Pasdepréfixe
&!
Notezenoutrequel'analyseurnevérifiepasleformateurdésignépourlasaisie.Rienne vous empêche de demander la saisie d'une chaîne avec %c ou d'une valeurdoubleavec%f(destinéautypefloat;pourletypedouble, ilfautstipuler%lf).
UtilisationdepointeurserrantsNousavonsvudansleChapitre13quepourutiliserunpointeurentoutesécurité,ilfallaitpasserpartroisétapes:déclarer,armeretutiliser.
Sivousoubliez l'étape2(fairepointer lepointeursursacible),vousallezsoit liren'importequoi,soit,etc'estplusgrave,écrireunevaleursanssavoiroù.
Boncourage!
AnnexeAInstallationdesoutils
DANSCECHAPITRE:
» OutilssurlignedecommandesousLinuxetMacOS
» InstallationdeCode::BlocksavecMinGW
» JavaSEJDK
» FirefoxDeveloperEdition
Nousavonsexpliquédansl'introductioncommentrécupérerlesfichierscompressés(desarchives)desexemplesquiillustrentcelivre.
Nous vous conseillons de créer un dossier depuis la racine de votre disque durprincipal(portantparexemplelenomPROGPLN)etd'ycopierlesfichiers.ZIPavantdelesdécompresser.
Pourexploitercesexemples,ilvousfautinstallerunatelierdedéveloppementouauminimum le compilateur libre GNU GCC. Cette opération est inutile si vouschoisissez d'installer un atelier complet tel queEclipse, qui fonctionne sur tous lessystèmes.
Nousmontrons plus loin dans cette annexe comment récupérer et installer l'atelierCode::Blocks,disponiblepourlestroissystèmes,maissurtoututilesousWindows.
OutilssousLinuxSous Linux, vérifiez d'abord si les compilateur GNU ne sont pas déjà en place.Ouvrezunefenêtredeterminaletsaisissezcettecommande:
gcc-v
S'ils n'y sont pas, vous les installez en un geste avec l'une des deux commandessuivantes:
sudoapt-getinstallbuild-essential
Ou:
sudoaptitudeinstallbuild-essential
Vérifiezensuiteavecunpremierexemplequetoutfonctionne.
SousMacOSXSous MacOS, vous pouvez choisir d'installer l'atelier de développement completXCode (gratuit après inscription sur le site des développeurs Apple). Selon laversion, il est ou pas fourni avec les outils de compilation CLT sur ligne decommande.
FIGUREA.1:L’espacedetravaildel’atelierXCodesousMacOS.
Pour de petits exemple en mode texte, cet atelier est surdimensionné (2 Go àtélécharger).Vouspouvezdoncn'installerquelescompilateurGNU(120Mo).Voicicomment:
1. Vérifiezsilesoutilsdelignedecommandesontdéjàprésents.
2. Ouvrezl'applicationTerminal(dossierApplicationssous-
dossierUtilitaires)etsaisissezcettecommande::
gcc-v
3. Silecompilateurn'estpastrouvé,procédezàl'installation
commececi:
xcode-select--install
Notezqu'ilyabiendeuxtiretsavantinstall.
4. Validezlesétapessuccessivespuispatientez.Unefoistout
installé,retentezdelancerlecompilateurcommeci-dessus.
Necherchezpasunenouvelleapplicationdansledossierhabituel.
LesoutilsCLTsontplacésdansundossiertechniquecommunsitué
danslaracinedusystème:
/Bibliothèque/Developer/CommandLineTools/
SousWindowsSousWindows,vouspouvez installeruniquement lesoutils sur lignedecommande,par exemple dans la distribution MinGW qui contient en plus de la chaîne deconstructionleslibrairiespourcréerdesapplicationspourWindows,doncenmodegraphique.
Unesolutionplusefficaceconsisteàmettreenplacel'atelierCode::BlocksenmêmetempsqueMinGW.
L’atelierCode::BlocksSurInternet,voustrouverezuncertainnombred’ateliersdeprogrammation,tousàpeuprèsdumêmeniveaudequalité.NousvousproposonsceluinomméCode::Blocks.IlestgratuitetfonctionnesousWindows,MacOSXetLinux.C’estunateliercomplet;vousn’aurezbesoinderiend’autre.
MiseenplacedeCode::BlocksVousdevezd’abordvousprocurerl’atelierCode::BlocksdepuislesiteWebofficielsuivant:
www.codeblocks.org
LesiteWebvacertainementévoluer,etladescriptionquisuitserapeut-êtreenpartieobsolète:
1. UtilisezvotrenavigateurWebpourvousrendresurlesitede
Code::Blocks.
2. CherchezleliendetéléchargementDownloads(danslemenu).
3. Cliquezleliendetéléchargementdesfichiersbinaires
(Downloadthebinaryrelease)appropriéàvotresystème.
4. PrenezsoindechoisirlaversionquicontientlecompilateurC,
parexemplecelledotéedeMinGW.
ParexemplepourWindows,lefichierporteunnomdanslestyle
suivant:
codeblocks-xx.yymingw-setup.exe
Lesxxetyycorrespondentaunuméromajeuretmineurdeversion
deCode::Block.
SousLinux,vouschoisissezentrelamouture32et64bitsen
fonctiondevotredistributionLinuxetduformatdel’archive.Jevous
conseilled’opterpourlaplusrécenteversionstable.
SousMacOSX,vousnepouvezchoisirqueleformatuniversel.zip.
5. Sinécessaire,procédezaudésarchivagedufichier
d’installationdeCode::Blocks.
MalgréletitredelacollectionPourlesnuls,jesupposequevoussavezquoifaired’unfichierauformat.zip,.gzou.dmgsurlesystème
quevousutilisez.
6. Lancezleprogrammeinstallateur.
Suivez les indications en optant pour une installation par défaut. Il est inutile depersonnaliserquoiquecesoitàceniveau.
SousWindows,vérifiezquevousinstallezlasuitedecompilation
MinGW.Sivousnevoyezcenomnullepartdanslafenêtrede
choixdescomposants,
c’estquevousn’avezpastéléchargélabonnevariantedeCode::Blocks.
Revenezdanscecasàl’Étape4.
7. Refermezlafenêtredel’installateur.
MêmesilafenêtredeCode::Blocksestapparue,ilestpossible
qu’ilfaillerefermerlafenêtredesoninstallateur.
Découvertedel’interfacedeCode::BlocksSi l’application Code::Blocks n’est pas encore démarrée, lancez-la maintenant ;cherchezsonicônesurleBureauoudansunmenu(dansWindows8,cherchezlenomCodeBlockssanslesdeuxsignesdeux-points).
La Figure A.1 présente l’aspect général de la fenêtre de l’espace de travail deCode::Blocks(workspace)constituédeplusieurssous-fenêtresoupanneaux.
FIGUREA.2:L’espacedetravaildel’atelierCode::Blocks.
LesdétailsnesontpastrèsvisiblesdanslaFigureA.2,maiscesontlesgrandeszonesqu’ilvousfautrepérer.Envoiciladescription:
Barres d’outils : Ces huit bandeaux horizontaux prennent place dans le haut de lafenêtre principale de Code::Blocks. Chaque barre offre une sélection d’icônes decommandes.Vouspouvezréarrangerlesbarres,enmasqueretenmontrer.Netouchezpasàleurdispositionavantd’avoirprisvosmarquesdansl’interface.
Fenêtredeprojets(Management):Lasous-fenêtredegaucheoffrequatreonglets,unseulmontrantsoncontenuàlafois.Cetespacerassembletouteslesressourcesdevotreprojetdeprogrammation.
Barred’état:Lebasdelafenêtreprincipaleestoccupéparuneséried’informationsconcernantleprojetencoursd’éditionetd’autrestémoinsrelatifsaufonctionnementdel’atelierCode::Blocks.
Éditeur(main.c):Lasurfacecentraledelafenêtreestdédiéeàlarédactionducodesource.
Journaux(Logs&others):Danslebasdelafenêtre,au-dessusdelabarred’état,prendplaceunesous-fenêtreavecunedouzained’ongletsaffichantdes informationstechniquessurleprojetencours.Levoletquevousutiliserezleplussouventestceluidesmessagesducompilateur,BuildLog.
DanslemenuprincipalView,voustrouverezdesoptionspourafficher/masquerlescomposantsdel’interface.ChoisissezparexempleView/Managerpourmasquerlepanneau gauche ou décidez quelles barres d’outils conserver par le sous-menuView/Toolbars.
Faites en sorte de ne pas être débordé par l’apparente complexité visuelle del’interface deCode::Blocks.Même si vous avez de l’expérience en programmationdansl’ancienstyle,untelatelierpeutintimiderdepartoutessesoptions,panneauxetvolets.Nevousinquiétezpas:ilnevousfaudraquepeudetempspourprendrevosmarques.
Pourprofiterdumaximumd’espaced’affichage,pensezàdéplierlafenêtreprincipalede Code::Blocks pour l’amener au format Plein écran. Vous devez pouvoir être àl’aise.
Chacune des sous-fenêtres et panneaux (Management, Éditeur, Logs) peut êtreretaillée : amenez le pointeur de souris entre deux zones et faites glisser dès qu’ilprendl’aspectd’unedouble-flèchepourajuster la largeuroulahauteurrelativedesdeuxzones.
Lepanneaudel’éditeurdecodeetceluidesjournauxenbassontmultivolets.Chaquezonepeutcomporterenhautplusieursongletspourbasculerd’unvoletàunautre.
InstallationducompilateurJavaJDKIlexistedenombreuseséditionsdeJavaetsurtout,Javaexisteendeuxmodèles:
» JavaRE(JRE)pourutilisateur(uniquementlamachinevirtuelleetles
librairies);
» JavaDevelopmentKit(JDK)pourdéveloppeur.
C'estleJDKqu'ilvousfaut.Choisissezl'éditionstandard,doncJavaSEJDK.L'outild'installationvousguideaulongdelaprocédure.Vérifiezensuitequetoutfonctionnedansunefenêtredeterminal:
javac-version
InstallationdeFirefoxDeveloperEditionSur le web, cherchez ce titre d'application Firefox Developer Edition. Vousdevriezarriverdirectementsurlapagedédiéedusitemozilla.org.Téléchargezetinstallez.Letourestjoué.
PratiquedesexemplesVousavezrécupéré lesarchivescompresséesdesexemplesdu livrecommeindiquédansl'introduction.Vousvoulezlesexpérimenter.
Si vous essayer les exemples du livre avec Code::Blocks, deux approches sontpossibles:
» Soitvouscréezunnouveauprojetpourchacund'eux,maiscela
vousfaitaccumulerdessous-dossierspourdesprojetstrèspetits.
» SoitvouscréezunprojetnomméTESTetvouscopiezlecode
sourcedechaquenouvelexempledanslefichiermain.cproposéau
départ,cequiécrasesoncontenu.Danscecas,pensezà
copier/collerlecontenuactueldansunautrefichiersivousvoulez
conservervosretouches.
Si vous faites une retouche dans le code source, pensez à adopter le bon réflexe :utilisez leboutonavec l'engrenageet la flèche(Généreretexécuter) pour quel'exécutablesoitconformeàvotreversionmodifiée.
AnnexeBTabledecaractèresASCII
Décimal Hexa Caractère Commentaires
7 0x07 ^G Bip,\a
8 0x08 ^H Retourarrière,backspace,\b
9 0x09 ^I Tabulation,\t
10 0x0A ^J Sautdeligne,linefeed,\n
11 0x0B ^K Tabulationverticale,\v
12 0x0C ^L Sautdepage,formfeed,\f
13 0x0D ^M Retourchariot,carriagereturn,\r
32 0x20 Espace,premiercaractèreaffichable
33 0x21 ! Pointd’exclamation
34 0x22 " Guillemetdroit(doublequote)
35 0x23 # Signedièse
36 0x24 $ Signedollar
37 0x25 % Pourcentage
38 0x26 & EsperluetteouEtcommercial
39 0x27 ' Apostrophe
40 0x28 ( Parenthèsegauche(ouvrante)
41 0x29 ) Parenthèsedroite(fermante)
42 0x2A * Astérisque
43 0x2B + Plus
44 0x2C , Virgule
45 0x2D - Tiret,moins
46 0x2E . Point
47 0x2F / Barreoblique
48 0x30 0 Chiffres
49 0x31 1
50 0x32 2
51 0x33 3
52 0x34 4
53 0x35 5
54 0x36 6
55 0x37 7
56 0x38 8
57 0x39 9
58 0x3A : Deux-points
59 0x3B ; Point-virgule
60 0x3C < Inférieurà,chevrongauche
61 0x3D = Égalité
62 0x3E > Supérieurà,chevrondroit
63 0x3F ? Pointd’interrogation
64 0x40 @ Arobase
65 0x41 A Alphabetencapitales
66 0x42 B
67 0x43 C
68 0x44 D
69 0x45 E
70 0x46 F
71 0x47 G
72 0x48 H
73 0x49 I
91 0x5B [ Crochetgauche
92 0x5C \ Antibarre(backslash)
93 0x5D ] Crochetdroit
94 0x5E ^ Circonflexe
95 0x5F _ Soulignement(underscore)
96 0x60 ` Accentgrave,apostrophegrave
97 0x61 a Alphabetenminuscules(basdecasse)
98 0x62 b
99 0x63 c
100 0x64 d
101 0x65 e
102 0x66 f
123 0x7B { Accoladegauche
124 0x7C | Barreverticale(pipe)
125 0x7D } Accoladedroite
126 0x7E ~ Tilde
127 0x7F Supprimer(delete)
Sommaire
Couverture
ProgrammerPourlesNuls3eédition
Copyright
Introduction
Pourqui,celivre?
Demandezleprogramme!
Préfacedeladeuxièmeédition
Structuredulivre
L'approche
Unartdeprogrammer?
Lapratique
Conventionstypographiques
Icônesutilisées
Remerciements
Avertissement
Gardonslecontact!
I.Premierscontacts
Chapitre1.Lecodeestpartout
Votretableurestprogrammable
Lafourmilièresouslecapot
Chapitre2.Uneséancedeprogrammationludique
EntrezdanslemondedeScratch
Créationd'unjeuenScratch
Enrouteverslaversion1.1
II.Lamachineàpenser
Chapitre3.Desmachines…
Lesmachinesmécaniques
Laféeélectricité
Etensuite?
Chapitre4....etdesnombres
Jour!Nuit!
Allô,labase?IcilecomteArbour
Lepouvoirdespuissancesdedeux
Calculonsenbase2
Comptezenbase2sansvousénerver
Lesnombresbinairesnégatifs
Demi-bitetquartdebit?
Lespuissancesnégativesde2!
N'oublionspaslabase16(hexadécimale)
Récapitulons
Chapitre5.Lesablequipense
JeuxdeBoole!
Porteslogiques
Circuitscombinatoires
Jemesouviens…(circuitsséquentiels)
Conclusiondelapartie
III.Fondamentaux
Chapitre6.Dompterlabête
Unécrivainélectrique?
Conditionsd'écriture
Conditionsmatériellesdecréation
Vueglobaled'untextesourceenC
Enavanttoute!
Chapitre7.Desvaleursauxdonnées
Valeursetespacemémoire
Leconceptdetypededonnées
Votrepremièrevariable
Leconceptd'instruction
Uneinstructionpourstockerlavaleur(=)
Expressionslibres
Transtypages
Tournuresdeconfort
Pourlesvariablesboudeuses:const
Lebooléenexiste,ouiounon?
Retoursurlesrebouclagesetdébordements
Récapitulatif
Fonctionnementlinéaire
Chapitre8.Tests,fourchesetredites
Sij'avaisunmarteau:exécutionconditionnelle
Lesopérateursrelationnels(opérels)
Lesopérateurslogiques(opélogs)
Lepostedebranchement:switch
Répétitiond'instructions:séquenceitérative
Tantqu'ilyauradel'amour:while
Jesaisforbiencompter:for
Compareretsauter,voilàtout!
Chapitre9.Enfonctiondevous()
Auloup!Auloup!goto
Leconceptdefonction
Sousleprogramme,lafonction
Choisirlemodedesfonctions
Étudedesquatremodes
Fonctiondemode1(LaMuette)
Fonctiondemode2(LaParame)
Fonctiondemode3(LaValeur)
Fonctiondemode4(LaMatheuse)
Annoncez-vous!(déclarationsetprototypes)
Lacitadelleduvassaletlesestrangers
Uneportéedevariableséphémères
Avoirlebraslong:variablesglobales
Jesous-traiteàmoi-même!Récursion
Chapitre10.Donnéesstructurées[]
Ungroupedevariablesanonymes
Utilisez-le,[maintenant]!
Enfinuntableautabulaire
Amessageinthetableau:leschaînes
Enfinlafonctionprintf()
Unflorilègedefonctionschaînes
Conclusion
Chapitre11.Leprocessusdeconstruction
Lesquatreétapesdelaconstruction
Constructionenuneétape
Unatelierdedéveloppement
Séancededébogage
Chapitre12.Librairies:surlesépaulesdesgéants
Librairieoubibliothèque?
Lesfonctionsstandard:unemalleautrésor
Lafamilledesentrées/sorties(stdio.h)
Autresfonctionsdedialoguedestdio.h
Lesfonctionsélémentairesdestdlib.h
Lesfonctionsmathématiques(math.h)
Lesfonctionstemporelles(time.h)
Leslibrairiesspécifiques
Chapitre13.Structuresetpointeurs
Desbâtimentslogiciels:struct
Lemondesecretdes*pointeurs
Pointeursettableaux
Pointeursetstructures
Transmettreunestructure
Lespointeurssontdesvariables!
Conclusiondelapartie
IV.Objetsetméthodes
Chapitre14.Programmationpilotéeparévénements
Dudactylocèneaucliquocène
Ouvronslafenêtre
L'applicationd'exemple
Etudedutextesource
Récapitulons
Chapitre15.Programmeravecdesobjets
Delaquasi-POOenC
C'estlaclasse!
Lesobjets:unvastesujet
UnexempleenC++
UnexempleenJava
RéutilisationdecodeetAPI
Swing
Récapitulons
Chapitre16.LangagesWebcôtéclient
Donnéeetinformation
L'ancêtreestparminous:le<SGML>
LeHTML:unSGMLpourtous
L'habitetlemoine(CSS)
Moteur,Action:JavaScript
HTML5etlesextensionsJS
V.Lesdixcommandements
Chapitre17.Dixpistesàexplorer
Lemondedulogiciellibre
Autreslangages
DéveloppementWebPHP
JavaScriptcôtéserveur(node.js)
LLVM,emscriptenetasm.js
Développementsgraphiques(OpenGL)
Visualisationdedonnées
Arduino/RaspBerryPietlarobotique
Réseauxdeneuronesetautomatescellulaires
Algorithmes
Chapitre18.DixerreursfréquentesenC
Bouclevideparpoint-virgulesuperflu
Oublidebreakdansswitch
Confusionde=etde==
Non-gestiondurestedesdivisionsentreentiers
Débordementd'unindicedetableau
Oublideprototype
Confusionentrecaractèresettableauxchaînes
Oubliduzéroterminaldanslestableauxchaînes
Erreursdescanf()
Utilisationdepointeurserrants
AnnexeA.Installationdesoutils
OutilssousLinux
SousMacOSX
SousWindows
L’atelierCode::Blocks
InstallationducompilateurJavaJDK
InstallationdeFirefoxDeveloperEdition
Pratiquedesexemples
AnnexeB.TabledecaractèresASCII
Recommended