Aide-memoire´ de Langage C -...

40
Aide-m´ emoire de Langage C Damien Mercier 6 f´ evrier 2000 Table des mati` eres 1 El´ ements de syntaxe 4 1.1 Structure g´ en´ erale d’un programme C .................................. 4 1.2 Un exemple complet ........................................... 4 2 La compilation sous Unix 5 3 Types, op´ erateurs, expressions 9 3.1 Les types simples ............................................. 9 3.2 eclarations des variables ........................................ 9 3.3 Types complexes, d´ eclarations de type .................................. 11 3.4 Ecriture des constantes .......................................... 12 3.5 Le transtypage (cast) ........................................... 13 3.6 Les op´ erateurs ............................................... 13 3.7 L’appel de fonction ............................................ 15 3.8 Les fonctions inline ............................................ 15 3.9 Les priorit´ es ................................................ 16 4 Tests et branchements 17 4.1 La conditionnelle ............................................. 17 4.2 Le switch ................................................. 18 4.3 Les boucles ................................................ 18 4.4 Les branchements ............................................. 19 5 Tableaux et pointeurs 19 5.1 eclaration et utilisation des tableaux .................................. 19 5.2 Les pointeurs ............................................... 20 5.3 Allocation dynamique de m´ emoire .................................... 21 5.4 Arithm´ etique sur les pointeurs ...................................... 22 5.5 Les chaˆ ınes de caract` eres ......................................... 23 5.6 Les pointeurs de fonction ......................................... 24 6 Le pr´ eprocesseur 25 6.1 L’inclusion de fichiers ........................................... 25 6.2 Les macros (#define) ........................................... 25 6.3 Compilation conditionnelle ........................................ 26 7 Fonctions d’entr´ ee/sortie 27 7.1 Le passage d’arguments en ligne de commande ............................. 28 7.2 Entr´ ee/sortie simples ........................................... 28 7.3 Entr´ ees/sorties avec format : fprintf(), fscanf() .............................. 29 1

Transcript of Aide-memoire´ de Langage C -...

Aide-memoiredeLangageC

DamienMercier

6 fevrier2000

Tabledesmatieres

1 Elementsdesyntaxe 41.1 Structuregeneraled’un programmeC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2 Un exemplecomplet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 La compilation sousUnix 5

3 Types,operateurs,expressions 93.1 Lestypessimples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93.2 Declarationsdesvariables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93.3 Typescomplexes,declarationsdetype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113.4 Ecrituredesconstantes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123.5 Le transtypage(cast) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133.6 Lesoperateurs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133.7 L’appeldefonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.8 Lesfonctionsinline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.9 Lespriorites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4 Testset branchements 174.1 La conditionnelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174.2 Le switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184.3 Lesboucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184.4 Lesbranchements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

5 Tableauxet pointeurs 195.1 Declarationetutilisationdestableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195.2 Lespointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205.3 Allocation dynamiquedememoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215.4 Arithmetiquesurlespointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225.5 Leschaınesdecaracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235.6 Lespointeursdefonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

6 Le pr eprocesseur 256.1 L’inclusiondefichiers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256.2 Lesmacros(#define) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256.3 Compilationconditionnelle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

7 Fonctionsd’entr ee/sortie 277.1 Le passaged’argumentsenligne decommande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287.2 Entree/sortiesimples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287.3 Entrees/sortiesavecformat: fprintf(), fscanf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

1

2 DamienMercier Aide-memoire deLangage C 6 fevrier2000

8 Complements: la biblioth equestandard et quelquesfonctionsannexes 298.1 � stdio.h� : entrees-sorties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308.2 � ctype.h� : testsdecaracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348.3 � string.h� : chaınesdecaractereset blocsmemoire. . . . . . . . . . . . . . . . . . . . . . . . . . . 358.4 � math.h� : fonctionsmathematiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368.5 � stdlib.h � : fonctionsutilitairesdiverses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368.6 � assert.h� : verificationsa l’execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388.7 � limits.h � , � float.h� : constanteslimites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388.8 � stdarg.h� : fonctionsanombrevariabled’arguments . . . . . . . . . . . . . . . . . . . . . . . . . 38

6 fevrier2000 Aide-memoire deLangage C DamienMercier 3

Intr oduction

Ce documentn’est pasun manuelde programmation,ni un supportde coursconcernantle langageC. Il s’agitsimplementd’un aide-memoirequi devrait permettrea tout eleve ayantsuivi le coursde C d’ecrirefacilementdesprogrammes.Il a ete ecrit a partir de l’excellentlivre de referencede B. W. Kernighanet D. M. Ritchie intitule LelangageC, C ANSI.

Le langageC dontil estquestionici estceluidefiniparlanormeANSI de1985(etsarevisionde1989).Neanmoins,quelquesajoutsserontfaits,commeparexemplele type long long, car ils sontsupportespar la plupartdescompila-teurs.De pluscertainsdesesajoutsserontintegresdansla prochainerevisiondela normeANSI, prevuepour2000anotreconnaissance.

Commeil esttresdifficile depresenterindependammentlesdifferentselementsd’un langage,il y auraparfoisdesreferencesa dessectionsulterieuresdansle coursdu texte.Cetaide-memoireestun documentdetravail et il nefautpashesiteraalleret venirdepageenpage.

Pouruneutilisationreguliereetefficacedu langage,il nesauraitetretrop recommandedecompletercepetit aide-memoireparunelecturedu livredereferencecite ci-dessus,enparticulierla partieAnnexeA: manueldereferencedela normeANSI et AnnexeB: La bibliothequestandard, dontun resumesuccinctestpresente a la fin decedocument.

Le C aetedeveloppeaudebut parDennisRitchie,puisBrianKernighan,auAT&T Bell Labsapartirde1972,pourunemachinede l’ epoque,le PDP-11.Le but etaitd’en faireun langageadapte pourecrireun systemed’exploitationportable.Le langagefut appele C caril heritait defonctionnalitesd’un precedentlangagenommeB et etait influenceparunautrelangagenommeBCPL.Le C aserviimmediatement(en1972-1974parKenThompsonetDennisRitchie)a reimplanterle systemeUnix (dontle debut du developpementdatede1970).Leslois anti-trustempecherontAT&Tde commercialiserUnix et c’est ainsi que le C et Unix serepandrontvia les universitesdansles annees1980.LeC est un langagetres utilise du fait de sa relative facilite d’utilisation, de son efficacite et de son adequationaudeveloppementdessystemesd’exploitations(graceenparticulieral’arithmetiquesurlespointeursetautypagefaible).On dit parfoisavec humourquec’est un langage qui combinel’ eleganceet la puissancede l’assembleuraveclalisibilit e et la facilite demaintenancedel’assembleur!

Certainesdesfaiblessesdu langage,enparticulierdesdifferencesdeplusenplusmarqueesentresesnombreusesimplantationset la necessited’uneboıte aoutils portableserontcorrigeesparla normeANSI de1985.Afin d’adapterle langageauxexigencesdedeveloppementdegrandeenvergure,sonsuccesseur, restantautantquepossiblecompa-tible auniveausource,serale C++, developpe parBjarneStroustrup,avecunephilosophieassezdifferente,maisenconservantla syntaxe.

4 DamienMercier Aide-memoire deLangage C 6 fevrier2000

1 Elementsdesyntaxe

1.1 Structure generaled’un programmeC

Pourrespecterla tradition,voici le programmele plussimpleecrit enC:

#include <stdio.h>main() {

printf("Je vous salue, O maitre.");}

Un programmeC estconstituede:

– Dir ectivesdu pr eprocesseurqui commencentparun# et dontnousreparleronsparla suite.Ici #include <stdio.h> permetdedisposerdesfonctionsd’entree-sortiestandardSTanDard Input/OutputHeader, enparticulierdela fonctionprintf() qui permetl’affichagea l’ ecran.

– Declarationsglobalesdetypeetdevariables,ainsiquedesprototypesdefonction,c’est-a-diredesdeclarationsdefonctionsou nefigurentquele nomdela fonction,lesparametreset le typedevaleurderetour, maissanslecorpsdela fonction.Il n’y ena pasdansl’exempleci-dessus.

– Fonctions. Tousles sous-programmesen C sontdesfonctions.Ce quel’on appellehabituellementprocedure(en Pascalpar exemple)est ici une fonction qui ne retournerien, ce qui sedit void en C. Le compilateurreconnaıt unefonctiona la presencedesparenthesesqui suiventle nomdela fonctionet a l’int erieurdesquellessetrouve la listedesparametres.Cettelistepeutetrevide commec’estle casci-dessuspourmain() .

– Une fonction particuli ere dont le nom estobligatoirementmain qui est la fonction appeleepar le systemed’exploitationlorsdu lancementdu programme.C’estla seulefonctiondanscetexemple.

1.2 Un exemplecomplet

Voici unexemplepluscompletmontrantla structuregenerale,avecunevariableglobaleiglob visibledepartout,les prototypesdesfonctions(indispensable1 pour la fonction somme() dansle caspresent)et les fonctions.Ceprogrammecalcule ��� d’unefacon un peudetournee...

#include <stdio.h>

/* variables globales */int iglob;

/* prototypes des fonctions */int somme(int a, int b);int produit(int a, int b);

/* fonctions */int produit(int a, int b) {

int sortie;

if (a>1) {sortie = somme(produit(a-1, b) , b);

} else {sortie = b;

}return sortie;

}

int somme(int a, int b) {return a+b;

}

1. En fait, en l’absencedeprototype,et si le texte dela fonctionn’a pasete rencontre jusqu’alors,le compilateurconsiderequ’elle retourneunint, cequi fonctionneici... maisn’estpasrecommande.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 5

/* programme principal */main() {

int j;j=1;for (iglob=1;iglob<=5;iglob++) {

/* appel de la fonction produit() */j = produit(iglob, j);

}printf("%d\n",j);

}

On remarquerades a presentqu’unefonction est formeed’un type, du nomde la fonctionsuivi de la liste despa-rametresentreparenthesespuisd’un bloc formantle corpsdela fonction.OnappelleblocenC toutensembledelimitepardesaccolades��� etcomportantdesdeclarationsdevariables(il peutnepasy enavoir) suivi d’expressions2. Il esttolere denepasfairefigurerdetypederetourpourunefonction(c’estle casdu main() ici), maisc’estunepratiquefortementdeconseillee.

Un prototypeala memeecriturequela fonction,acelapresquele blocducorpsdela fonctionestremplaceparunpoint-virgule.Lorsqu’il serafait referencea desfonctionsprovenantd’unebiliothequedansla suitedecedocument,celles-ciserontpresenteesparleur prototype.

2 La compilation sousUnix

Exempleelementaire

Le compilateurC sousUnix fourni avecla machines’appellegeneralementcc. Neanmoinson utilise souventgcccar il estpresentpartout,il supportela normeANSI ainsiquequelquesextensionsbienpratiques,il estlibre et tresefficacesurtouteslesmachines.C’estparailleursle seulcompilateurC dignedecenomdisponiblesurlessystemesd’exploitationlibres(Linux, FreeBSD,NetBSD).

La compilationsefait dansle casle plussimplepar:Idefix> gcc <source.c> -o <executable>

ou il fautbienentenduremplacerleschaınesentre<> parlesbonsnomsdefichiers.Si desbibliothequessontnecessaires,parexemplela bibliothequemathematique,onajoutea la lignedecommande

precedente-l<bibliotheque> , (-lm pourla bibliothequemathematique).

Options du compilateur gcc

gccacceptedetresnombreusesoptions(voir la pagedemanuelman gcc). Envoici quelquesunesfort utiles:-g Compilationaveclesinformationsutilespourle deverminage(debug).Avecgcconpeutainsiutili-

serl’excellentdeboggueurgdb (ou la versionavecinterfacegraphiquexxgdb).-ansi Forcele compilateura etreconformea la normeANSI. Lesextensionscommeles long long sont

neanmoinsacceptees.-pedantic Le compilateurrefusetout cequi n’estpasstrictementconformea la normeANSI. Ceci,combine

avec -ansi permetde verifier qu’un programmeeststrictementconformea la normeet donc entheorieportable.

-Wall Forcel’affichagedetouslesmessagesd’alertelors dela compilation.-O Optimisationde la compilation.Il vaut mieux ne l’utiliser que lorsquele programmefonctionne

deja demanierecorrecte.Desoptimisationsencorepluspousseessontpossiblesavec-On, ou n estun entierentre1 et4 engeneral.L’optimisationconduisantparfois a desdeplacementsd’instructions,il estdeconseille d’executeraudevermineurdesprogrammesoptimises.

-I � rep� Precisele(s)repertoire(s)ou il fautchercherlesfichiersdeheader(include).-D � var=val � Permetdedefinir desvariablesdu preprocesseur. -DDEBUG=2estequivalenta mettreaudebut du

sourcela ligne#define DEBUG2. Onpeutegalementecrire-DMONOPTIONqui estequivalenta #define MONOPTION3.

2. C’estl’ equivalentdubegin...endduPascal.3. Il s’agit dedirectivesdupreprocesseurqui serontpresenteesenpartie6.

6 DamienMercier Aide-memoire deLangage C 6 fevrier2000

-S Le compilateurgenereuniquementle listing assembleur(et non du codeobjet ou un executable),avecpardefautle suffixe .s. C’estutile pouroptimiserefficacementdetrespetitsmorceauxdecodecritiques(ouparsimplecuriosite!).

-M Permetd’extraire desreglesde dependance(envoyeessur la sortiestandard)pour le programmemake, defacon similairea makedepend(cf. page8).

-p L’executablegenere integredesfonctionsdemesuredetempspasse,nombred’appels...(profiling).Lors du lancementde cet executable,un fichier gmon.out estgenere, et les resultatssontconsul-tablesulterieurementavecgprof <nom_de_l’ex ecutable> .

De nombreusesautresoptions d’optimisation sont disponibleset peuvent influencersensiblementla rapidited’executiondansle casdeprogrammestrescalculatoires.

Compilation separee

La programmationmodulaireconsisteanepasregrouperdansunseulfichier tout le codesourced’un projet,maisaucontrairea le repartirdansplusieursfichierset a compilercesderniersseparement.Cecipermetunereutilisationsimpledu codecar un ensemblede fonctionsd’usagegeneral peut etre isole dansun fichier et reutilise facilementdansd’autresprogrammes.De plus, pour les grosdeveloppementslogiciels, la compilationestuneetapelongueachaquemodification;il estdoncsouhaitabledeseparerlessourcesenplusieurspetitsfichiers,ainsiseulslesfichierseffectivementmodifiesdevront etrerecompilesa chaquefois.

Afin derendrele sourced’un projetle pluslisible possible,onadoptegeneralementquelquesconventionssimples.Ondistingueainsitrois typesdefichierssources:

– Desfichierscontenantdesfonctionsqu’onnommeraavecuneextension.c, maisnecontenantenaucuncasunefonctionmain() .

– Desfichierscontenantlesdeclarationsde type, les prototypesdesfonctions(voir plus loin) et eventuellementdesmacros,correspondantauxsourcesprecedentes.On lesnommeracommelessourcesauxquellesils corres-pondentmaisavecun suffixe .h, et ils serontincluspardesdirectives#include danslessourcesdesfichiers.c. Onappellecesfichiersdesheaders(en-tetes).

– Desfichiersavecuneextension.c, contenantun main() et utilisant lesfonctionsdesautresfichiers(qui sontdeclareespar desinclusionsdes .h). Chaquefichier de ce type donneraun executabledu projet final. Il estrecommande d’adopteruneconventionclaire de nommagede cesfichiersafin de les distinguerdespremiers(parexemplelesnommerm_<nom_executable>.c ou main.c s’il n’y enaqu’un).

La compilationd’un fichier source.c enun fichier objetayantle memenomdebasemaisle suffixe .o sefait parunecommandedu type:Idefix> gcc -c <source.c>Rappelonsqu’unfichierobjetestenfait unfichiercontenantlecodecompiledusourcecorrespondant,maisou figurentegalement(entreautre)unetabledesvariableset desfonctionsexporteesdefiniesdansle source,ainsiqu’unetabledesvariableset desfonctionsqui sontutiliseesmaisnondefinies.

Les fichiers objets(.o) sont alors li es ensemble,c’est la phased’edition de liens, ou sont egalementajouteesles bibliotheques(ensemblede fonctionsprecompilees).Danscettephase,les tablesde tousles fichiersobjetssontutiliseespour remplacerles referencesaux variableset aux fonctionsinconnuespar les vrais appels.Le resultatestalorsun fichier executable.Cecisefait parunecommmandedu type:Idefix> gcc <obj1.o> <obj2.o> ... <objn.o> -o <executable> -lm

Il convient de bien faire la differenceentre la ligne #include <math.h> et l’option -lm sur la ligne decommande.Eneffet, le headermath.h contienttouslesprototypesdesfonctionsmathematiques,maisnecontientpasleurcodeexecutable.Le codepermettantdecalculerle logarithmeparexemplesetrouveenfait dansunebibliothequeprecompilee.C’estl’option d’editiondelien -lm qui fournit la fonctionelle-memeenajoutantauprogrammele codedecalculdesfonctionsdela bibliothequemathematique.

Les bibliothequesprecompileessontstockeessousUnix commedesfichiersarchive portantl’extension.aa. Lors del’utilisation de -l<nom> , le fichier recherche s’appelleenfait lib � nom .a, et setrouve generalementdans/usr/lib .Il estdoncpossiblemaisfortementdeconseille deremplacerla ligneIdefix> gcc <obj1.o> <obj2.o> ... <objn.o> -o <executable> -lm

par

Idefix> gcc <obj1.o> <obj2.o> ... <objn.o> /usr/lib/libm.a -o <executable>

a Il existe egalementd’autre typesde bibliothequeset le mecanismereel d’edition de lien est un peu plus subtil que nous lepresentonsici, neanmoinsle comportementqualitatif restele meme.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 7

Makefile

Gardertracedesdependances4 desfichiersentreeux et realisermanuellementles phasesde compilationseraitfastidieux.Un utilitaire generiquepourresoudrecegenredeproblemesdedependancesexiste: make. Sonutilisationdepasselargementla compilationdeprogrammesenC. La versionutiliseeici estGNU make,accessiblesousle nommake sousLinux et sousle nomgmakesousSUNSolaris.

make fonctionneensuivantdesreglesqui definissentlesactionsa effectuer. Il cherchepardefautcesreglesdansun fichier nomme Makefile dansle repertoirecourant.Voici un exemplesimplequi permetde compilerles fichiersfich.c etm_tst.c enun executabletst :

## Makefile# L’ex ecutable depend des deux fichiers objetstst : fich.o m_tst.o

gcc fich.o m_tst.o -o tst # ligne de compilation a ex ecuter

## Chaque fichier objet depend du source correspondant# mais egalement du header contenant les prototypes des fonctionsfich.o : fich.c fich.h

gcc -c fich.c

m_tst.o : m_tst.c fich.hgcc -c m_tst.c

La premiereligne d’uneregleindiquele nomdu fichier concerne(appelefichier cible) suivi dedeux-points(: ) etdela liste desfichiersdontil depend.Si l’un decesfichiersestplusrecent5 quele fichier cible,alorslescommandessitueessur les lignessuivant la reglesontexecutees.Ainsi, si tst doit etre fabrique, la premierereglenousdit quefich.o et m_tst.o doivent d’abordetrea jour. Pourcela,make tentealorsde fabriquercesdeuxfichiers.Unefois cettetacheeffectuee(cesontlesdeuxautresreglesqui s’enchargent),si le fichier nomme tst estplusrecentquefich.o et m_tst.o , c’est termine, dansle cascontraire,tst est refabrique par la commandequi suit la reglededependance: gcc fich.o m_tst.o -o tst .

Attention le premiercaractered’unelignedecommandedansunMakefileestunTAB (caracteredetabulation)et nondesespaces.

Avec le Makefile ci-dessus,il suffit ainsi de tapermake tst (ou mememake, car tst est la premiereregleren-contree)pour fabriquerl’executabletst. make n’executeque les commandesde compilationnecessairesgraceauprocedederesolutiondesdependancesexpliciteeci-dessus.

make peutservir a la generationautomatiquede fichiersd’impressiona partir de sourcesLATEX... Il peut per-mettred’automatiserapeupresn’importequellesequenced’actionsystematiquesurdesfichiers.L’envoi parcourrierelectroniquedu projetenC estunexemple(aamenagersi voussouhaitezl’utiliser) :

# Envoi automatique de mail pour le projet# A remplacer par le bon nomNOM=monnomPROF=gueydan

# Les sources du projetSRCS= Makefile interface.c calcul.c \

fichiers.c m_projet.c

mail.txt: explication.txt $(NOM).tar.gz.uucat explication.txt $(NOM).tar.gz.uu > mail.txt

mail: mail.txtmail -s IN203 gueydan < mail.txt

4. Ondit qu’unfichierdependd’un autre,si le premierdoit etrereconstruitlorsquele secondchange.Ainsi unfichierobjetdependdesonsourceet detouslesheadersinclusdansle source.

5. Lesdependancessontverifieesapartir dela datededernieremodificationdechaquefichier.

8 DamienMercier Aide-memoire deLangage C 6 fevrier2000

$(NOM).tar.gz.uu: $(SRCS)tar cvf $(NOM).tar $(SRCS)gzip -c $(NOM).tar > $(NOM).tar.gzuuencode $(NOM).tar.gz $(NOM).tar.gz > $(NOM).tar.gz.uu

Voici enfinunexemplegeneriquecompletpourcompilerlessourcesinterface.c , calcul.c , fichiers.cetm_projet.c . Lespremiereslignesdel’exemplesontdescommentaires(commenc¸antpar#), etexpliquentle roledu projet.

Il estfait usageici del’utilitaire makedependpourfabriquerautomatiquementlesdependancesduesauxdirectives#include . En effet, chaquefichier objet dependd’un fichier sourcemaisausside nombreuxheadersdont il estfastidieuxdegarderla liste a jour manuellement.makedependparcourtle sourcea la recherchedecesdependanceset ajouteautomatiquementlesreglescorrespondantesa la fin du fichier Makefile (lesreglesainsiajouteesa la fin nesontpasreproduitesci-dessous).makedependestunoutil faisantpartiedeX11, gcc-M peutjouerle memerolemaissonutilisationestun peupluscomplexe.

L’usagedevariables(CFLAGS, LDFLAGS...) permetderegrouperlesdifferentesoptionsaudebut du fichier Ma-kefile. La variablecontenantla listedesfichiersobjetsestobtenueautomatiquementparremplacementdesextensions.c par .o.

Descaracteresspeciauxdansles reglespermettentd’ecriredesreglesgeneriques,commeici la generationd’unfichier objetayantl’extension.o a partir du sourcecorrespondant.Un certainnombredecesreglessontconnuespardefautparmake si ellesnefigurentpasdansle fichier Makefile.

################################### ###### ##### ##### ###### ##### ##### ###### ECOLE : ENSTA# PROJET : Cours IN261# FONCTION : Compilation du projet# CIBLE : UNIX / make ou GNU make# AUTEUR : MERCIER Damien# CREATION : Thu Sep 23 10:02:31 MET DST 1997 sur Obiwan# MAJ : Tue Jan 12 20:18:28 MET 1999 sur Idefix# Version : 1.02################################### ###### ##### ##### ###### ##### ##### ###### Le compilateur utilis eCC=gcc# Options de compilationCFLAGS=-I. -ansi -g -Wall# Options d’ edition de liensLDFLAGS=-lm

# Le nom de l’ex ecutablePROG= projet# La liste des noms des sources (le caractere \ permet de passer# a la ligne sans terminer la liste)SRCS = interface.c calcul.c \

fichiers.c m_projet.c

# La liste des objetsOBJS = $(SRCS:.c=.o)

################################### ###### ##### ##### ###### ##### ##### ###### Regles de compilation################################### ###### ##### ##### ###### ##### ##### ###### Regle par defaut : d’abord les dependances, puis le projetall: dep $(PROG)

# Ajout automatique des dependances entre les .c et les .h# a la fin de ce Makefiledep:

6 fevrier2000 Aide-memoire deLangage C DamienMercier 9

makedepend -- $(CFLAGS) -- $(SRCS)

# Comment compile t’on un .c en un .o ? (Regle generique)%.o : %.c

$(CC) $(CFLAGS) -c $*.c

# L’edition de liens$(PROG) : $(OBJS)

$(CC) $(CFLAGS) $(OBJS) -o $(PROG) $(LDFLAGS)

# ’make clean’ fait un nettoyage par le videclean:

\rm -f $(PROG) $(OBJS) Makefile.bak *˜ #* core

3 Types,operateurs,expressions

3.1 Les typessimples

Les typesdebaseenC sontlesnombresentiers(int ), lesnombresreels(float) et lescaracteres(char). Certainsdecestypesexistentenplusieurstailles:

char representeun caracterecodesurun octet(8 bits);

int designeun entiercode sur la taille d’un mot machine,generalement32 bits sur les machinesac-tuelles;

short (on peutaussiecrireshort int ) designeunentiersur16 bits;

long (ou long int ) designeun entiersur32 bits;

float estun nombreflottant(reel)simpleprecision,generalementcodesur32bits;double estun flottantdoubleprecisioncode le plussouventsur64 bit ;

long double estun flottantquadrupleprecision.Il n’estpasgarantiquesagammesoit superieurea un double.Celadependdela machine.

Le mot cle unsignedplace avant le typepermetdedeclarerdesnombresnon-signes.De la memefacon, signedpermetdepreciserquele nombreestsigne.En l’absencedespecification,touslestypessontsignes,a l’exceptiondechar qui estparfoisnon signe par defaut6. Il convient de noterquele type char peutservir a stocker desnombresentierset peutservircommetel dansdescalculs.La valeurnumeriquecorrespondanta un caracteredonneestenfaitsoncodeASCII.

Les tailles citeesci-dessussontvalablessur unemachinestandard dont le mot elementaireest16 ou 32 bits etpourun compilateurstandard : autantdirequ’il estpreferabledeverifieravant...

3.2 Declarationsdesvariables

Unedeclarationdevariablesefait systematiquementau debut d’un bloc avanttouteautreexpression7.La declarations’ecrit <type> <nom>; ou <type> estle typede la variableet <nom> estsonnom.On peut

regrouperplusieursvariablesdememetypeenuneseuledeclarationenecrivantlesvariablessepareespardesvirgules:int a, b, i, res; par exemple.Remarquerquececi estdifferentdesparametresd’une fonction,qui doiventtousavoir un typeexplicite (on ecrit int somme(int a, int b); ).

Toutevariabledeclareedansunblocestlocaleacebloc,c’est-a-direqu’ellen’estpasvisibleendehorsdecebloc.De plus,elle masquetoutevariablevenantd’un bloc qui l’englobe.Cecipeutsevoir surun exemple:

#include <stdio.h>int a, b;

dummy(int a) {/* la variable a globale est ici masquee

par le parametre a, en revanche b est globale */

6. Avecgcc, le typechar estsigne ou nonselonlesoptionsdecompilationutiliseessur la ligne decommande: -fsigned-charou -funsigned-char.

7. Cettelimitation devrait etreleveedansla futurenormeANSI.

10 DamienMercier Aide-memoire deLangage C 6 fevrier2000

/* on a a=3 a l’appel 1 (provient du c du main()), b=2 (globale) *//* et a=5 a l’appel 2 (provient du d du sous-bloc), b=2 (globale) */

/* c et d ne sont pas visibles ici */printf("%d %d\n",a,b);

}

main() {int c, d;a=1; b=2; c=3; d=4;dummy(c); /* appel 1 *//* on a toujours a=1, b=2 globales

et c=3, d=4 locales */{ /* sous-bloc */

int d, b;d=5; /* d est locale a ce bloc et masque le d de main() */b=7; /* b est locale a ce bloc */dummy(d); /* appel 2 */

}printf("%d\n",d); /* on revient a d=4 du bloc main() */

}

Ceprogrammeaffichedansl’ordre:

3 25 24

Attention , la simpledeclarationd’unevariableneprovoquegeneralementaucuneinitialisationdesavaleur. Si celaestneanmoinsnecessaire,onpeutecrirel’initialisation avecunevaleurinitiale sousla forme int a=3; .

Lesclassesde stockage

On appelledecenombarbarelesoptionsqui peuventfigurerentetedela declarationd’unevariable.Lesvaleurspossiblessontlessuivantes:

auto Il estfacultatif etdesignedesvariableslocalesaubloc,alloueesautomatiquementaudebut du blocet libereesenfin debloc.Onnel’ ecrit quasimentjamais.

register Cettedeclarationestsimilaireaauto , maispourun objetaccede tresfrequemment.Celademandeaucompilateurd’utiliser si possibleun registredu processeurpourcettevariable.Il esta noterquel’on nepeutdemanderl’adressememoired’unevariable(par l’operateur& presente enpartie5.2)ayantcettespecification,celle-cin’existantpas.

static Lesvariablesnonglobalesainsideclareessontalloueesdefaconstatiqueenmemoire,etconserventdoncleur valeurlorsqu’onsortdesfonctionsetdesblocsetquel’on y entreanouveau.Dansle casdesvariablesglobalesetdesfonctions,l’ef fet estdifferent: lesvariablesglobalesdeclareesstatiquesnepeuventpasetreaccedeesdepuislesautresfichierssourcedu programme.

extern Lorsqu’unsourcefait appela unevariableglobaledeclareedansun autresource,il doit declarercelle-ciextern, afindepreciserquela vraiedeclarationestailleurs.Enfait unevariableglobaledoitetredeclareesansrien dansun source,et declareeextern danstousles autressourcesou elle estutilisee.Cecipeutsefaireenutilisantle preprocesseur(cf. 6).

En reglegenerale,il estpreferabled’eviter l’utilisation de la classeregisteret laisserau compilateurle soin duchoixdesvariablesplaceesenregistre.

Afin desimplifier la tachededeveloppementet pour limiter les risquesd’erreurs,il estrecommande dedeclareravecle mot clestatic entetelesvariableset fonctionsqui sontglobalesauseindeleurfichier, maisqui nedoiventpasetreutiliseesdirectementdanslesautressources.

En revanche,utiliser static pour desvariableslocalespermetde conserver une information d’un appeld’unefonctiona l’appel suivantde la memefonctionsansnecessiterdevariableglobale.Ceciesta reserver a quelquescastresspeciaux: nepasenabuser!

6 fevrier2000 Aide-memoire deLangage C DamienMercier 11

3.3 Typescomplexes,declarationsde type

Le C estun langagedontla vocationestd’ecrireducodedetresbasniveau(manipulationdebits),commecelaestnecessaireparexemplepourdevelopperun systemed’exploitation8, maisil disposeegalementdefonctionnalitesdehautniveaucommelesdefinitionsdetypecomplexe.

Trois famillesdetypesviennents’ajouterainsiauxtypesdebase,il s’agit destypesenumeres, desstructur esetdesunions. Cestrois typessedeclarentdefaconsimilaire.

Le type enumere esten fait un type entierdeguise. Il permeten particulierde laisserdesnomslitt erauxdansun programmepour en faciliter la lecture.Les valeurspossiblesd’un type enumere font partie d’un ensembledeconstantesportantun nom,quel’on appelledesenumerateurs.L’exemplesuivantdefinit un typeenumere correspon-dantadesbooleens,notebool, et declareenmemetempsunevariabledecetypenommeebvar :enum bool {FAUX, VRAI} bvar;Aprescettedeclarationil estpossiblededeclarerd’autresvariablesdecememetypeaveclasyntaxeenum bool au-trevar; .

Dansla premieredeclaration,il estpermisd’omettrele nomdu typeenumere (danscecasseulela variablebvar auracetype)oubiendenepasdeclarerdevariablesurla lignededeclarationd’enumeration.

Dansuneenumeration,si aucunevaleurentieren’estprecisee(commec’est le casdansl’exempleprecedent),lapremiereconstantevautzero,la deuxieme1 etainsidesuite.La ligneci-dessusestdoncequivalentea (sansnommagedu type)

enum {FAUX=0, VRAI=1} bvar;

Lorsque’ellessontprecisees,lesvaleurspeuventapparaıtredansn’importequelordre:

enum {lun=1,ven=5,sam=6,mar=2,mer=3,jeu=4 ,dim= 7} jour;

Une structur e est un objet compose de plusieursmembresde typesdivers,portantdesnoms.Elle permetderegrouperdansuneseuleentiteplusieursobjetsutilisablesindependemment.Le but estderegroupersousunseulnomplusieurselementsdetypesdifferentsafin defaciliter l’ ecritureet la comprehensiondu source.

Unestructurepixel contenantlescoordonneesd’un pixel etsescomposantesdecouleurpourraparexempleetre:

struct pixel {unsigned char r,v,b;int x,y;

};

Par la suite,la declarationd’unevariablep1 contenantunestructurepixel seferaparstruct pixel p1; .

La remarqueprecedenteconcernantlespossibilitesdedeclarationdesenumerationss’appliqueegalementauxstructureset auxunions.

Les accesaux champsd’une structuresefont par l’operateurpoint (. ) . Rendrele point p1 blancsefera ainsi parp1.r = 255 ; p1.v = 255 ; p1.b = 255 ;

Uneunion estunobjetqui contient,selonle moment,undesesmembreset unseul.Sadeclarationestsimilaireacelledesstructures:

union conteneur {int vali;float valf;char valc;

};union conteneur test;

En fait, il s’agit d’un objetpouvantavoir plusieurstypesselonlescirconstances.Onpeutainsiutiliser test.vali commeun int , test.valf commeunfloat ou test.valc commeunchar

apresla declarationprecedente,maisun seula la fois !La variabletest estjusteun espacememoireassezgrandpourcontenirle membrele pluslargedel’union, et tous

lesmembrespointentsur la memeadressememoire.Il incombedoncauprogrammeurdesavoir quel typeeststockedansl’union lorsqu’il l’utilise : c’estunedesraisonsqui rendentsontusagepeufrequent.

8. C a ete developpe audepartcommele langageprincipaldusystemeUnix.

12 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Attention , il estfortementdeconseille d’utiliser la valeurd’un membred’uneunionapresavoir ecrit un autremembrede la memeunion (ecrireun int et lire un char par exemple)car le resultatpeutdiffererd’une machinea l’autre (etpresenteengeneralpeud’interet, saufsi l’on veutsavoir l’ordre quela machineutilise pourstocker lesoctetsdansunlong...).

Declaration de type

Celle-cisefait aumoyendu mot-cle typedef. Un nouveautypeainsidefini peutservirpar la suitepourdeclarerdesvariablesexactementcommelestypessimples.Onpeutainsiecriretypedef unsigned char uchar;

afind’utiliser uchar a la placedeunsigned char danslesdeclarationsdevariables...La declarationde type est tres utile pour les enumerations,les structureset les unions.Dansnotre exemple

precedent,il estpossibled’ajoutertypedef struct pixel pix;

pourensuitedeclarerpix p1,p2; . Uneversionabregeeexisteegalementdanscecasetpermetenuneseulefois dedeclarerla sructurepixel et le typepix :typedef struct pixel {

unsigned char r,v,b;int x,y;

} pix;

Le comportementestalorsexactementle memequeci-dessus: lesdeclarationsstruct pixel p1; et pix p1;sontequivalentes.

Il estpossibleaussidesupprimercompletementle nomdestructuredanscecasenecrivant:typedef struct {

unsigned char r,v,b;int x,y;

} pix;

Commeprecedemment,lesdeclarationsdevariablesulterieuresseferontparpix p1; .

Maisattention, cettederniereecriturenepermetpasderealiserlesstructuresautoreferentiellesqui sontpresenteesau5.2.

3.4 Ecritur e desconstantes

Les constantesentieressontecritessousformedecimale,octale(base8) ou hexadecimale(base16). L’ ecrituredecimalesefait de facon naturelle,l’ ecritureoctales’obtientenfaisantprecederle nombred’un 0 (parexemple013vautendecimal11),et l’ ecriturehexadecimaleenfaisantprecederle nombredu prefixe0x.

De plus, il estpossibled’ajouterun suffixe U pour unsignedet/ouL pour long dansle casou la valeurde laconstantepeutpretera confusion.Ainsi 0x1AUL estuneconstantedetypeunsignedlong et valant26.

Les constantesde type caracterepeuventetreentreessousformenumerique(par leur codeASCII, cardu pointde vue du compilateurce sont desentierssur un octet), il est aussipossiblede les ecrire entreapostrophes(e.g.’A’ ). Cettederniereecritureaccepteegalementles combinaisonsspecialespermettantd’entrerdescaracteresnon-imprimablessansavoir a memoriserleur codeASCII (voir au paragraphe5.5). Le caractere ’\0’ vaut la valeur 0(appeleeNUL enASCII) etsertdemarqueurspecial9.

Il faut bien remarquerquele type caracterecorresponda un caractereunique(memesi certainscaracteressontrepresentespardeschaınesd’echappementscomme’\n’ ) et nona unechaınedecaracteres.

Les constantesflottantes (qui correspondenta dex nombresreels)peuventutiliser unesyntaxe decimaleou unenotationscientifiqueavecla lettree pourmarquerl’exposant.

Il estpossibled’affecterunevaleur a unevariablelors de sadeclaration.Ceci se fait le plus simplementpos-siblepar int a=3; . Dansle casou cettevariableesten fait uneconstante(c’est un comble!), c’est-a-direqu’ellene peut et ne doit pas etre modifiee dansle corpsdu programme,on peut preciserconst devant la declaration:const float e2 = 7.3890561 .

9. Le chiffre ’0’ vautenfait enASCII 48

6 fevrier2000 Aide-memoire deLangage C DamienMercier 13

Cettememesyntaxe d’affectationinitiale peutsefairepour lesstructures,les enumerationset les tableaux.Pourlesstructures,lesvaleursinitialesdoivent etreecritesentreaccolades,separeespardesvirguleset dansl’ordre de lastructure.Il estpossibled’omettrelesdernierschampsdela structure,qui prennentalorspardefautla valeurzero:

typedef struct {unsigned char r,v,b;int x,y;

} pix;

pix p1={2, 3, 4, 5, 6}; /* r=2 v=3 b=4 x=5 y=6 */pix p2={1, 2}; /* r=1 v=2 b=0 x=0 y=0 */

constsertegalementa preciserquecertainsargumentsdefonction(dansla declaration,et s’il s’agit depointeurs,cf. 5.2)designentdesobjetsquela fonctionnemodifierapas10.

3.5 Le transtypage(cast)

Lors de calculsd’expressionsnumeriques,les typesflottantssontdits absorbantscar la presenced’un uniquenombreflottantdansuneexpressionentraıneuneevaluationcompletesousformedeflottant.

Il est frequentqu’unevariableait besoind’etreutiliseeavecun autretype quesontype naturel.Celaarrive parexemplesi l’on veutcalculerle quotientdedeuxentiersetstocker le resultatdansunreel(voir le paragraphesuivant).

Ce transtypages’obtient en faisantpreceder l’expressionque l’on souhaiteutiliser avec un autre type par cetype entreparentheses.C’est par exemplele seul moyen de convertir un nombreflottant en entier, car une fonc-tion floor() estbiendefiniedansla bibliothequemathematique,maiselle retourneun nombreflottant! On ecriraainsi i = (int)floor(f); .

Le transtypaged’entierenflottantet reciproquementcommepresente ci-dessusestun castresparticulier, qui pourraitlaissercroirequetouteslesconversionssontpossiblesparcebiais.Attentiondonc,dansla grandemajorit edescas, letranstypageconduitjusteainterpreterle contenudela memoired’uneautrefacon: c’estle casparexemplesi l’on essaiedetransformerunechaınedecaracterechar s[10] enun entierpar(int)s , et le resultatn’a pasd’interet (enfaitcelarevient a lire l’adressememoirea laquelleeststockees !). Poureffectuerlesconversions,il convient d’utiliser lesfonctionsadequatesdela bibliothequestandard.

3.6 Les operateurs

Les operations arithm etiquesen C sontd’ecritureclassique: +, -, *, / pour l’addition, la soustration,lamultiplication et la division. Il est a noterque la division appliqueea desentiersdonnele quotientde la divisioneuclidienne.Pourforcerunresultatennombreflottant(etdoncunedivisionreelle),il fautconvertir l’un desoperandesennombreflottant.Parexemple3/2 vaut1 et 3/2.0 ou3/(float)2 vaut11 1.5.

Lesaffectationss’ecriventavecle signe=. Unechoseimportanteestanoter: uneaffectationpeutelle-memeetreutiliseecommeun operandedansuneautreoperation,la valeurdecetteaffectationestalorsle resultatdu calcul dumembrededroite.Ainsi on pourraparexempleecrirea=(b=c+1)+2; dont l’action estdecalculerc+1 , d’affecterle resultata b, d’y ajouter2 puis d’affecter le nouveauresultata a. Il est a noterquece type d’ecriture,saufcasparticuliers,rendla lectureduprogrammeplusdifficile et doit doncetresi possibleevite.

Les operations booleennespermettentde fairedestests.Le C considerele 0 commela valeurfausseet touteslesautresvaleurscommevraies.Pourcombinerdesvaleursentantqu’expressionbooleenne,onutilise le OU logiquenote || et le ET logiquenote &&. La negationd’une valeurbooleennes’obtientpar ! place avant la valeur. Il estimportantdereteniregalementquelesoperateurslogiques&&et || arretentl’ evaluationdeleursargumentsdesquecela estpossible12. Cettepropriete peutetreinteressante,parexempledansdesconditionsde fin de boucledu typeSI monindicen’a pasdepasse lesbornesET quelquechosequi dependdemonindiceALORS instructions. En effetdanscecasle calculqui dependdel’indice n’ESTPAS effectuesi l’indice adepasse lesbornes,cequi estpreferable!

Il restea engendrerdesgrandeursbooleennesqui represententquelquechose! Ceci ce fait avec les operateursde comparaison. Le testd’egalitesefait par== (deuxsignesegal),le testd’inegalite (differentde)sefait par != , larelationd’ordrepar>, . >=, < et<=.

10.L’usagedeconstestparticulierementimportantpourlessystemesinformatiquesembarques,ou le codeexecutableet lesconstantespeuventetrestockesenmemoiremorte(ROM).

11. Il s’agit ici d’un transtypage(cast).12.Cecis’appellede l’ evaluationparesseuse(lazyevaluation).

14 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Attention uneerreurclassiqueestd’ecrireun seulsigneegaldansun test.Commele resultatd’uneaffectationestlavaleuraffecteeet commeun nombrenonnul estun booleenvrai, ecrire:

if (a == 2) {printf("a vaut 2\n");

}

ou ecrire:

if (a = 2) {printf("a vaut 2\n");

}

esttresdifferent! (la deuxiemeversionestun testtoujoursvrai, et a vaut2 apresl’execution).

Lesoperations d’incr ementationet de decrementation etantfrequentessurlesentiers,il estpossible(et memerecommande) d’ecrire i++ plutot que i=i+1 . Commedansle casdesaffectations,l’operationd’incrementationaunevaleur, qui est la valeuravant incrementationsi le ++ esta droite de la variable,et est la valeurincrementeesic’est++i . Un operateurdedecrementationnote -- existeegalement.En resume:

/* valeurs apres la ligne */i = 2; /* i=2 */a = ++i; /* i=3, a=3 */b = a--; /* b=3, a=2 */b++; /* b=4 */

On remarqueraque,bien quel’operateurait unevaleurderetour, celle-cipeutetreignoree.Ceciestvrai egalementpourlesfonctions.Parexempleprintf() quenousavonsutilise toutaudebut retournenormalementun int , maisle plussouventon ignorecettevaleurderetour.

Dansla ligneedesoperateursd’incrementation,il existetout unefamille d’operateurs de calcul-affectation quimodifientunevariableenfonctiond’uneexpression.Leur syntaxe estdela forme<var.> R= <expr.> ou R estuneoperationparmi+, - , * , / , %, >>, <<, &, | et ˆ . L’ ecritureprecedenteestalorsequivalentea:<var.> = <var.> R <expr.> .

Quelquesoperateursspeciauxviennents’ajoutera cela: nousavonsdeja parle desfonctions,l’appel de fonctionestun operateur(c’est memel’operateurde priorite maximale).Il y a egalementl’operateurconditionnel dont lavaleurresultatprovientd’unedesdeuxexpressionsqu’il contientselonunecondition:<Condition> ? <Expression si vraie> : <Expression si fausse>La conditionestuneexpressionbooleenne.Elle estsystematiquementevaluee(avec un arret desquele resultatestcertaincommenousl’avons vu precedemment)et selonsavaleur, une desdeuxexpressionset uneseulementestevaluee.Un exempled’usageestla constructiond’unefonctionMIN :

int min(int a, int b) {return ( (a>b) ? b : a );

}

Un dernieroperateursouventpasse soussilenceestl’op erateur vir gule. Il permetdeseparerunesuited’expressionsqui serontnecessairementevalueesl’une apresl’autre de la gaucheversla droite, le resultatfinal de cettesequenced’expressionetantle resultatdela derniereevaluation(expressionla plusa droite).

Lesoperateursconcernantlespointeurset lestableauxserontpresentesenpartie5.

Lesoperateurssur lesbits d’un mot sontextremementutilesenprogrammationbas-niveauetpermettentgenera-lementd’eviter la programmationen langagemachine.Lesoperationsagissentbit a bit sur la representationbinairede leur(s)operande(s).On disposeainside la complementation(˜ ) detouslesbits d’un mot, du ET bit a bit, du OUet du XOR (OU eXclusif) notes respectivement&, | et ˆ . Les operateursde decalagea gauche(equivalent a unemultiplicationpardeuxsurdesentiersnonsignes)et adroite(divisionpar2) senotent<< et>>. Quelquesexemples:

unsigned char c, d;c=0x5f; /* en binaire 0101 1111 */d = ˜c; /* d = 0xA0 1010 0000 */d = d | 0x13; /* 0x13 = 0001 0011 -> d = 0xB3 1011 0011 */c = d ˆ (c << 2); /* c decale a gauche 2 fois : 0111 1100 */

resultat c= 0xCF 1100 1111 */

6 fevrier2000 Aide-memoire deLangage C DamienMercier 15

Attention une autre erreur classiqueconsiste a oublier un signe et a ecrire cond1 & cond2 au lieu decond1 && cond2 dansun test.Le compilateurne peut bien sur rien remarqueret l’erreur estgeneralementtresdifficile a trouver.

3.7 L’appel de fonction

En C, l’appel defonctionsefait par le nomdela fonctionsuivi de la liste desparametresentreparentheses.Uneparticularite tresimportantedu langageestquelesparametrespassesenargumentde la fonctionsontrecopiesdansdesvariableslocalesa la fonctionavantle debut desonexecution.Onappellecelaunpassagepar valeur. Ainsi, sansutiliser lespointeurs13, le seulresultatqui puissesortir d’un appeldefonctionestsavaleurderetour.

La fonction se terminelorsquel’executionatteint l’accoladefermantedu bloc, et dansce casil n’y a pasdevaleurde retour(la fonction doit etredeclareede type void ). Si la fonction doit retournerunevaleur, celle-ci doitetrepreciseepar l’instruction return 14. L’executiondecetteinstructionterminela fonction.Il estpossibled’avoirplusieursinstructionsreturn dansunememefonction,parexempledansle casdetests.

Dansle casd’unefonctionretournantvoid (sansvaleurderetour),return ; permetdeterminerla fonction.Voici unexemple:

#include <stdio.h>int test(int a, int b) { /* lors de l’appel, a=2 et b=7 */

if (a==0) return b;/* la suite n’est execute que si a != 0 */a=b/a;b=a;return a;

}main() {

int x, y, z;x=2; y=7;z=test(x,y); /* z=3 mais x et y ne sont pas modifies */

/* seule leur valeur a ete copiee dans a et b de test() */printf("%d %d %d %d\n",x,y,z,test(0,z)); /* affiche 2 7 3 3 */

}

Lesfonctionspeuventbiensur etrerecursives,commele montrel’exempledu 1.2.

3.8 Les fonctions inline

L’ ecriturede programmeslisibles passepar le decoupagedesalgorithmesen de nombreusesfonctions,chacuneformantuneunite logique.Certainesdecesfonctionsneserventqu’unefois, maisonpreferenepasintegrerleurcodea l’endroit ou ellessontappelees.A l’in verse,d’autresfonctionssont tressimples(quelqueslignesde programme,commeparexemplele calculdu minimumdedeuxvaleurs)et sontutiliseesun grandnombredefois.

Dansles deuxcas,chaqueappelde fonction estunepertede tempspar rapporta ecrire le codedirectemental’endroit de l’appel (le compilateursauvegardele contexte audebut de l’appel de fonction,placeeventuellementlesargumentssurla pile, puisappellela fonction)le retourdel’appel estegalementassezcouteux.

Poureviter cegachisdepuissancedecalcul, la plupartdescompilateursessayentd’optimiserenplacant le codedecertainesfonctionsdirectementa la placedeleurappel.Ceciadenombreuseslimitations: il fautcompileravecdesoptimisationsforteset lesfonctionsconcerneesdoiventetredansle memefichier source15

Pouraiderle compilateurdansle choixdesfonctionsaoptimiserainsi,il estpossibledepreciserle mot-clefinlineaudebut dela declarationdela fonction.Ceciprendalorseffet memesi lesoptimisationsnesontpasdemandees(cen’estqu’uneindication,commela classeregisterpourlesvariables).

Cemot-clef inline nefait paspartiedela normeANSI actuelle,maisestsupporte pargccet denombreuxautrescompilateurs,et devrait fairepartiedela nouvellenorme.

13.Voir 5.2.Ceux-cipermettentquelquechosedesimilaireaupassageparvariable(ouparreference)duPascal.14.Onpeutindifferemmentecrirereturn n; ou return(n); , c’estuneaffairedegout. La deuxiemeecritureayantl’avantagededonnerun

petit air defonctiona return .15.Cecin’empechepasla compilationseparee,maistout appeldefonctionentredesfichiersobjetsdifferentsestobligatoirementeffectue sous

la formed’un vrai appeldefonction.A cettefin, le compilateurconserve toujoursuneversiondela fonctionappelablenormalement.

16 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Pourpermettrel’appel de fonctiondepuisd’autresfichiersobjeta, le compilateurconserve tout dememeuneversionsousformedefonctionclassique,saufsi la fonctionestdeplusdeclareestatic inline.

a C’estegalementnecessairesi la fonctionestappeleequelquepartparpointeurdefonction,cf. 5.6.

On pourraavec avantagedeclarerainsi unefonction minimum de deuxentierssousla forme de fonction inline(plutot quedemacro,cequi conduita defrequenteserreurs):

static inline int min(int a, int b) {return ( (a>b) ? b : a );

}

Cesfonctionsdeclareesstatic inline sont les seulesfonctionsquel’on pourraecriredansles fichiers .h afin depouvoir lesutiliser commeon le fait avecdesmacros.

3.9 Les priorit es

Voici un tableaurecapitulatifdonnanttouslesoperateurset leur priorite (la premiereligne du tableauestla plusprioritaire,la derniereestla moinsprioritaire),lesoperateursayantdesprioritesegalesfigurentdansunememeligneet sontevaluesdansle sensindiquedansla colonneassociativite:

Operateurs Fonction Associativite priorite

() appeldefonction maximale[] elementdetableau . champdestructureou d’union

-> champdesigneparpointeur ! negationbooleen �˜ complementationbinaire �- oppose �

++ incrementation �-- decrementation �& adresse �* dereferenciationdepointeur �

(type) transtypage �* multiplication / division % resteeuclidien + addition - soustraction

<< decalagea gauche >> decalagea droite < strictementinferieur

<= inferieurou egal > strictementsuperieur

>= superieurou egal == egal != different & ET bit a bit ˆ OU eXclusif (XOR) bit a bit | OU bit a bit

&& ET booleen || OU booleen

? : conditionnelle �= affectation �

*= /= %= affectationsaveccalcul �+= -= <<= affectationsaveccalcul �

>>= &= |= ˆ= affectationsaveccalcul �, sequenced’expressions minimale

6 fevrier2000 Aide-memoire deLangage C DamienMercier 17

Lesoperateursconcernantlespointeurssontpresentesau5.

Cetableauesttresimportant,et sonignorancepeutconduireparfoisa deserreursdifficiles a detecter. Citonsparexamplea=*p++ : lesoperateurs++ et * sontdememepriorite,doncl’expressionestevalueedansl’ordre d’associa-tivite (dedroitea gauche),et doncp estincremente,et l’anciennevaleurdep estdereferencee,le resultatetantstockedansa. Si l’on veut incrementerla valeurpointeeparp (et nonp lui-meme),il faudraecrirea=(*p)++ . Le resultatstockedansaestle memedanslesdeuxcas.

Encasdedoute,il nefautpashesiteramettrequelquesparentheses(sansabusertoutefois)carcelapeutaidera lacomprehension.On eviteraainsid’ecrire: a=++*p>b|c+3 !Oneviteraaussi: a=((++(*p)>b)|(c+3)) etonprefereraquelquechosecomme: a = ++(*p)>b | (c+3) .

4 Testset branchements

4.1 La conditionnelle

Nousavonsvu lorsdel’examendesoperateursl’expressionconditionnelle.Il existeegalementbiensur unestruc-turedecontrolequi realisel’executionconditionnelle.Sasyntaxeestla suivante:if (<condition>) {

<instructions ...>}

La conditionest testeecommeun booleen,c’est-a-direqu’elle estconsidereecommevraie si son evaluationn’estpasnulle. Dansle casou uneseuleinstructionesta executerquandla conditionestvraie,on trouverasouventcetteinstructiontouteseulea la placedu bloc entreaccolades.La versionavecalternative:if (<condition>) {

<instructions ...>} else {

<instructions ...>}

La encoreil estpossiblederemplacerl’un ou l’autre (ou lesdeux)blocsentreaccoladesparuneuniqueinstruction.Attentiondanscecas,il fautterminercetteinstructionparunpoint-virgule.Avecdemultiplesalternatives:if (<cond1>) {

<instructions ...> /* Si cond1 est vraie */} else if (<cond2>) {

<instructions ...> /* si cond1 fausse et cond2 vraie */} else {

<instructions ...> /* si cond1 et cond2 fausses */}

}

De nombreuxprogrammesC utilisentdestestssansinstructiondecomparaisonexplicite, voire destestsqui sontle resultatd’operationsd’affectation,parexemple:if (a = b - i++) i--; else a=b=i++;

Ceci utilise le fait qu’une valeur non nulle est consideree commevraie. C’est assezdifficile a lire, aussiil serapreferable16 d’ecrirecetteversionequivalente:i++;a= b-i;if (a != 0) {

i--;} else {

i++;b = i;a = b;

}

16.A moinsquel’on souhaitebattrele recorddel’ ecrituredu jeu detetrisenunminimumdelignes!

18 DamienMercier Aide-memoire deLangage C 6 fevrier2000

4.2 Le switch

switch (<expression>) {case <val 1>: <instructions ...>case <val 2>: <instructions ...>...case <val n>: <instructions ...>

default: <instructions ...>}

L’instructionswitch permetdediriger le programmeversunesequenced’instructionschoisieparmiplusieurs,sui-vantla valeurd’uneexpressionqui doit etredetypeentier.

Le branchementsefait a l’ etiquettecase dontla valeurestegalea l’expressiondetete(il nedoit y avoir auplusqu’uneetiquettequi correspond).Si aucuneetiquettenecorrespond,le sautsefait a l’ etiquettedefault si elleexiste.

Attention,unefois le branchementeffectue,le programmecontinuedes’executerdansl’ordre,y comprislescasequi peuventsuivre.Pourempechercecomportement,on utilise souventbreak a la fin desinstructionsqui suiventlecase : soneffet estdesauterdirectementapresle bloc du switch (Voir 4.4).

Un exemplecompletd’utilisationstandard:

int val,c;c=1;val = mafonctiondecalcul(); /* une fonction definie ailleurs */switch (val) {

case 0:case 1: printf("R esultat 0 ou 1\n");

c=2;break;

case 2: printf("R esultat 2\n");break;

case 4: printf("R esultat 4\n");c=0;break;

default: printf("Cas non pr evu\n");}

4.3 Les boucles

La bouclefor

C’estunebouclebeaucoupplusgeneralequedansd’autreslangages.Sonroleneselimite pasa la simplerepetitionenincrementantun entier. Sonutilisationestla suivante:

for ( <inst. initiale> ; <cond. de poursuite> ; <inst. d’avancement> ) {<instructions ...>

}

L’ instructioninitiale estexecuteeavant le debut de la boucle,la conditiondepoursuiteesttesteea chaquedebut deboucleet l’ instructiond’avancementestexecuteeenderniereinstructionachaquetour deboucle.

L’ equivalentdela boucled’incrementationd’unevariableentieredesautreslangagess’ecriraparexemple:

for (i=0; i<100; i++) {<instructions...> /* ex ecut ees pour i=0, i=1 ... i=99 */

}

Onpeutomettren’importelaquelledestroisexpressionsdela bouclefor. Si c’estla conditiondepoursuitequi estomise,la bouclesecomportecommesi cetteconditionetaittoujoursvraie.Ainsi uneboucleinfinie17 peuts’ecrire:

for (;;) {<instructions ...>

}

17.Qui neseterminejamaissi l’on utilisepaslesinstructionsdebranchementqui serontpresenteesau4.4.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 19

La bouclewhile

while (<condition de poursuite>) {<instruction ...>

}

qui estcompletementequivalentea (remarquerquelesexpressionsdela bouclefor sontfacultatives):for (;<condition de poursuite>;) {

<instructions ...>}

De facon similaire, il est possiblede reecrire une boucle for generiquesousla forme d’une bouclewhile .L’ ecrituregeneriqueprecedenteestequivalentea:<inst. initiale>;while (<cond. de poursuite>) {

<instructions...><inst. d’avancement>;

}

La boucledo...while

Ici le testesteffectueenfin deboucle.Cetteboucleestdonc,contrairementauxdeuxbouclesprecedentes,executeeaumoinsunefois, memesi la conditionestfaussedesle debut dela boucle.Voici la syntaxe:do {

<instructions ...>} while (<condition de poursuite>);

4.4 Les branchements

Cesontdesinstructionsqui modifientle deroulementd’un programmesanscondition.L’instructioncontinue nepeutetrepresentequ’a l’int erieurd’uneboucle.Elle conduita un branchementversla

fin dela pluspetitebouclequi l’entoure,maisnesortpasdela boucle(ainsi l’ instructiond’avancementsi elle existeesteffectuee,puisla bouclereprend).

L’instruction break peut apparaıtre dansune boucle ou dansune instruction switch . Elle effectue un sautimmediatementapresla fin de la boucleou du switch . Sonusageest indispensabledansle casdesbouclesinfi-nies.

L’instructiongoto � label � quanta elle peutapparaıtren’importeou. Elle effectueun sauta l’instruction qui suitl’ etiquette<label>: (cetteetiquettesenoteparle labelsuivi dedeux-points).

L’usagedu goto estfortementdeconseille car il conduitfrequemmenta un sourceillisible. Il peutdansquelquesrarescasrendreserviceenevitantd’immensesconditions,oudenombreusesrepetitionsd’un memepetitmorceaudecode.

L’exemplesuivant montre l’utilisation de break et de continue au sein d’une boucle for . On trouvera plusfrequemmentl’instruction breakdansdesbouclesinfinies.for (i=0; i<100; i++) {

if (i<5) continue; /* si i<5 la fin de la boucle n’est pas ex ecut ee */if (i==10) break; /* si i vaut 10 la boucle se termine */printf("%d\n",i);

}

Le resultatdecetteboucleestl’affichagedesnombres5, 6, 7, 8, 9. La conditiondepoursuitedela bouclefor estenfait totalementinutile ici.

5 Tableauxet pointeurs

5.1 Declaration et utilisation destableaux

En C, un tableaua une dimensionde 10 entiersseradeclare par la syntaxe int x[10]. Il s’agit d’une zonedememoirede longueurdix entiersqui estalloueeautomatiquement,x etantcommeexplique ci-dessousun pointeurconstantversle premierentierdecettezone.

20 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Lesdix cellulesdutableausontalorsaccessiblesparx[0] ax[9]. Il convientdenoterqu’aucuneverification n’estfaite sur la validit e du numero de la casedemandeedu tableau.L’accesa unecaseaudela du dernierelementdutableau(ou avant le premier, par exemplex[-1]) peutconduirea uneerreur, maisil sepeutaussiquecelaaccedead’autresvariablesduprogrammeet danscecas,l’erreur esttresdifficile adetecter...

Les tableauxde plusieursdimensionsexistent egalement,par exemplechar pix[128][256] . L’accesauxcasesdecetableausefait alorsparpix[i][j] , i et j etantdesentiers.Il fautvoir cetyped’ecriturecommel’accesa un tableaua uneseuldimensionde128elementsqui sontchacunsdestableauxde256caracteres.

L’affectationde valeursinitiales dansun tableaua unedimensionsefait au moyen d’une liste de valeursentreaccolades:

int a[10]={1,2,3,4};

Danscetexemple,a[0] , a[1] , a[2] eta[3] sontinitialises,a[4] aa[9] nele sontpas.Onpeutomettred’ecrirela taille du tableau,le compilateurla calculealorsen comptantle nombred’elementsfournis pour l’initialisation :int a[]={1,2,3,4} conduit alors a un tableaude quatreelementsseulement.Pour les tableauxde plusieursdimensions,le dernierindicecorrespondaunombredecolonnesdu tableau:

int b[2][4]={{1,2,3,4}, {5,6,5,6}}; /* 2 lignes, 4 colonnes */

Danscecas,seulle premierindicepeutetreomis, le compilateurcomptantqu’il y a deuxlignes,maisne comptantpasles colonnessur chaqueligne. Il estmemepossibledansce casde ne pasassignertousles elementsde chaqueligne! Ainsi

int b[][4]={{1,2}, {5,6,5}};/* 2 lignes (comptees par le compilateur), 4 colonnes */

conduita un tableaudedeuxlignesetquatrecolonnesdontseulslesdeuxpremierselementsdela premierelignesontaffectes,ainsiquelestroispremierselementsdela deuxiemeligne18.

5.2 Les pointeurs

Un pointeuresten fait unevariablespecialedanslaquelleon ne stocke pasla valeurquel’on desireconserver,maisseulementsonadresseen memoire.En C un pointeursur un objet de type typ estunevariablede type notetyp * . Ainsi la declarationint *x; definit x commeun pointeursurunevaleurde type int , c’est-a-direcommel’adressememoired’un entier.

L’accesaucontenud’un pointeursefait pardereferenciationavecl’operateuretoile.La valeurpointeeparx peutdoncetreaccedeeparl’expression*x .

Un pointeurestunevariablequi a sapropreadresse,et qui contientl’adressedela variablesur laquelleil pointe.Ainsi, la declarationint *x; allouela casememoirecorrespondantaupointeurx , maisn’initialise passavaleur.Or cettevaleurdoit etre l’adressede l’entier pointe par *x . En consequence,la dereferenciationde x provoqueraprobablementune erreur(ou un resultatstupide...)tant que l’on n’a pasecrit explicitementdansle pointeuruneadressevalide.

Pourinitialiser la valeurdu pointeurx , il fautainsiutiliser uneadressememoirevalide,parexemple,celled’uneautrevariable.A ceteffet, l’adressed’unevariables’obtientparl’operateur&. Ainsi si l’on adeclare int y,*x; onpeutecrirex = &y; . Le pointeurx pointealorssurla casememoirecorrespondanta la valeurdela variabley . Tantquele pointeurx n’estpasmodifie,*x et y ont toujoursla memevaleur(c’est la memecasememoire).On peutvoir* commel’operateurinversede&. Ona ainsi*(&y) qui vauty , et dememe&(*x) qui vautx .

Un pointeuresten fait unevariablepresquecommelesautres.Il s’agit d’un entierde la taille d’uneadressememoiredela machine(le plussouvent32bits).La variablepointeurx denotreexempleprecedentestunentierdesignificationspeciale.Il estdoncpossibledeprendrel’adressed’un pointeur! Le pointeur&x estalorsun pointeurversun pointeursurun entier, il contientl’adressedel’adressedel’entier. Sontypeestint ** .

Cespossibilitessonttout particulierementinteressantespour lesappelsdefonction.En effet, si on passeenargu-mentd’unefonctionl’adressed’unevariable,la fonctionva pouvoir modifierla variablelocaleparl’intermediairedesonadresse.L’adresseestrecopieedansun pointeurlocal, on nepeutdoncpasla modifier, maisenrevanchela casememoirepointeeestla memeet peutdoncetremodifiee.Voici un exemple:

int exemple(int x, int *y)

18.Lesvariablestableauxglobalessontpardefaut initialiseesa zero,ainsiquelesvariableslocalesdeclareesstatic , enrevanchelesvariablestableauxlocalesnormales(nonstatiques)NE sontPAS initialisees.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 21

{x += 3;*y += x;return(x);

}

main(){

int a,b,c;

a = 2;b = 1;c = exemple(a,&b);printf("a=%d b=%d c=%d\n");exit(0);

}

Danscet exemple,le programmeaffiche a=2 b=6 c=5 . La variableb a ete modifieepar l’appel de fonction: onparlealorsd’effetdebord.

Pourecrireunefonctionqui modifie la valeurd’un pointeur(et passeulementl’ elementpointe commeci-dessus),ilfaudrapasserenparametrea cettefonctionl’adressedupointeura modifier, c’est-a-direun pointeursurle pointeur.

Lorsquel’on definit despointeurssur desstructures,il existe un raccourciparticulierementutile (st est ici unpointeursurunestructurecontenantun champnommechamp) :(*st).champ estequivalenta st->champ , l’operateurfleches’obtenantparla successiondessignes- et >.

Lespointeurssontegalementutilesdanslesappelsdefonctionmemesi la fonctionn’a pasamodifierla valeurpointee:il esten effet beaucoupplus efficacede passeruneadressea unefonction quede recopierun grosbloc de memoire(on evite ainsi generalementde passerdesstructuresentieresen parametre,on prefereun pointeursur la structure).L’accesauxchampsd’unestructurereferenceeparunpointeurestainsile casd’ecriturele plusgeneral,d’ou la syntaxespeciale.

Lorsquela fonctionnemodifiepasl’objet pointe,onutiliseraavantageursementle motcleconstqui permetaucompila-teurdeverifierqu’aucuneecrituren’estfaitedirectementdansl’objet pointe(cen’estqu’uneverificationrudimentaire).

Une derniere utilisation communedes pointeursest le cas de fonctions pouvant prendreen parametre des zonesmemoiresdont le type n’est pasimpose. On fait cela au moyen du pointeurgeneriquede type void * , qui peutetreaffecteavecn’importequelautretypedepointeur. Un exempletypiquedecetteutilisationestla fonctionmemset()(definiedans<string.h> ) qui permetd’initialiser un tableaudedonneesdetypequelconque.

5.3 Allocation dynamiquede memoire

Pourpouvoir stockerenmemoireunevaleurentiere,il fautdoncexplicitementdemanderuneadressedisponible.Ilexisteheureusementun autremoyend’obtenirdesadressesmemoirevalides,c’estle role dela fonctionmalloc() .Son prototypeest void *malloc(size_t size); . Le type size_t est un type special, on pourraretenirqu’il s’agit en fait d’un entiercodantun nombred’octetsmemoire.La taille d’un objet de type donne s’obtientparl’operateursizeof() , applique a la variablea stockerou a sontype.

Ainsi on pourraecrire

int *x;/* on peut aussi ecrire x=(int *)malloc(sizeof(*x)); */

x = (int *)malloc(sizeof(int));*x = 2324;

cequi :

1. Declarela variablex commeunpointeursurunevaleurdetype int .

2. Affectea x uneadressedansla memoirequi estreserveepour le stockaged’une donneede taille sizeof(int),doncdetype int .

3. Placela valeur2324a l’adressex.

22 DamienMercier Aide-memoire deLangage C 6 fevrier2000

L’appel malloc(s) reserve en memoireun bloc de taille s. On remarqueque la fonction malloc() retourneun pointeurde type void * : on appellecelaun pointeurgenerique(c’est le type de pointeurquemanipulentlesfonctionsqui doivent travailler independammentde l’objet pointe). Il faut bienentendule convertir dansle type dupointeurquel’on desiremodifieretcecisefait partranstypage.

La memoireainsialloueele restejusqu’a la fin du programme.C’estpourcelaquelorsqu’onn’a plusbesoindecettememoire,il convient depreciserqu’elle peuta nouveauetreutilisee.Cecisefait par la fonction free() dontl’argumentdoit etreun pointeurgenerique.La taille n’a pasbesoind’etrepreciseecar elle estmemorisee lors del’appel a malloc() . Dansle caspresent,la liberationdela memoireseferait par free((void *)x); .

Du fait desmethodesutiliseespour gerercetteallocationdynamique,il estpreferabled’eviter de faire de tresnombreusesallocationsdetrespetitsblocsdememoire.Si celaestnecessaire,on ecrirasaproprefonctiondegestionmemoire,enfaisantlesallocationset liberationsavecmalloc() et free() pargrosblocs19.

5.4 Arithm etique sur lespointeurs

Un pointeurest en fait un entier un peu special puisqu’il contientune adressememoire.Certainesoperationsarithmetiquessont disponiblesafin de permettrela manipulationaisee de blocs de memoire contenantplusieurselementsconsecutifsdu memetype.

On disposeainsi de l’addition d’un pointeurp et d’un entier n qui donneun pointeurde memetype que p,pointantsurle n-iemeelementdubloc commenc¸anta l’adressepointeeparp. Parexemplep+0 vautp etpointedoncsur l’ elementnumerozero,p+1 pointesur l’ elementsuivant...Ceci fonctionnequellequesoit la taille de l’ elementpointe parp, p+n provoquantainsiun decalaged’adressescorrespondantenoctetsa n fois la taille del’objet pointeparp.

Il estpossibleaussid’effectuerla soustractionde deuxpointeursde memetype,et celadonneun resultatentierqui correspondaunombred’elementsqui peuventetreplacesentrecesdeuxpointeurs.L’exemplesuivantmontreunefacond’initialiser un blocmemoire(cen’estpasla methodela plussimplepoury arriver, maiselle estefficace):

#define TAILLE 1000typedef struct pixel {

unsigned char r,v,b;int x,y;

} pix;

main() {pix *p;pix *q;

p=(pix *)malloc(sizeof(pix)*TAILLE);

for (q=p;q-p<TAILLE;q++) {q->r=q->v=q->b=0;q->x=q->y=0;

}...

}

Il existedessimilaritesentrelestableauxet lespointeurs.Enparticulier, un tableauaunedimensionestenfait unpointeurconstant(il n’estpaspossibledemodifier l’adressesur laquelleil pointe)versla premierecasedu tableau.Ainsi il y a une equivalencetotale entre les ecrituresp[i] et *(p+i) lorsquep est un pointeurou un tableaumonodimensionnelet i unentier(char, int ou long) 20.

19.L’inefficacite de la gestionpar petitsblocsvient entreautrede l’ensembledesparametresstockespour chaquemalloc() effectue, qui peutatteindre16 octets! D’ou, pourallouerun bloc de1024*1024elementsdetypechar, environ 1 Mo si celasefait parun appelmalloc(1024*1024)et environ 17Mo si celaestfait en1024*1024appelsamalloc(1)...

20.On amemeequivalenceavec i[p] bienquecettederniereecrituresoit a eviter!

6 fevrier2000 Aide-memoire deLangage C DamienMercier 23

Attention , il n’y a pasequivalencesimpleentreunedereferenciationdepointeuret un accesa un tableaua plusieursdimensions.Il fauten fait voir un tableaua deuxdimensionsint tab[3][5] commeun tableaudetrois elementsqui sontdestableauxdecinq entiers(et nonl’inverse).Cestrois elementssontstockeslesunsa la suitedesautresenmemoire.

Les ecritures tab[i][j] , *(tab[i]+j) , *(*(tab+i) +j) et *((int *)tab+5*i+j) sont alorsequivalentes,maisil restefortementconseille pourla lisibilit e deselimiter a la premiere.

De faconsimilaire,le passaged’un tableauenparametreaunefonctionpeutsefairedefacon equivalentesousla formed’un pointeur(void test(int *a) ) etsousla formed’un tableausanstaille (void test(int a[]) ). Danslecasdetableauxa plusieursdimensions...la deuxiemesolutionesttresfortementdeconseille,on vousauraprevenu! Sile typeestunsimplepointeurversle debut dutableauadeuxdimensions,il faudradoncfournir egalementa la fonctionla taille du tableau(tout cecipeutsemettredansunejolie structure,commeon le fait parexemplepourdesimages).

5.5 Les chaınesdecaracteres

LeschaınesdecaracteressontrepresenteesenC sousla formed’un pointeursurunezonecontenantdescaracteres.La fin de la chaıneestmarqueepar le caracterespecial ’\0’ . Il estpossibled’utiliser la declarationsousformedetableau: char ch[256]; definit unechaınedontla longueurmaximaleestici de256caracteres,encomptantle caracteredeterminaison.En fait, parconvention,toutechaınedecaractereseterminepar le caracterenul (pasle chiffre ’0’ ,maisl’entier 0 note souventpourcetteutilisation ’\0’ ). La chaınedecaracterepeutaussisedeclarersousla formed’un pointeurchar * , versunezonequ’il fautalloueravecmalloc() .

On peut ecriredeschaınesconstantesdelimiteespar desguillemets.L’expression"chaine\n" estdoncunechaınecomportantle mot chaine suivi d’un retourchariot,et commetoujourstermineeparuncaractere’\0’ .

La fonction strlen(s) (declareedans � string.h� dansla bibliothequestandard)retournela longueurde lachaıne s jusqu’aupremiercode ’\0’ 21. La fonction strcmp(s1,s2) permetde comparerdeux chaınes.Elleretourne-1 si lexicographiquements1

�s2 , 0 si lesdeuxchaınessontidentiques,et +1 si s1 � s2 .

Pourl’anecdote,cettefonctionestequivalentea strlen() (!) :int mystrlen(char *s) {

int longueur;for (longueur=0; *s++;longueur++) ;return longueur;

}

Lesstructur esautoreferentielles22

Ce sont desstructuresdont un desmembresest un pointeurvers une structuredu memetype. On les utilisecourammentpourprogrammerdeslisteschaıneeset pourlesarbres.

Voici un exemplesimplemaiscomplet,danslequella liste initiale estalloueeen un bloc consecutif et chaınee,puisensuiteutiliseecommeunelistechaıneequelconque:

#include <stdio.h>#include <stdlib.h>

typedef struct liste {struct liste *suivant;int valeur;

} tliste;

main() {tliste *maliste;tliste *temp;int i,som;

21. Il s’agit du nombredecaractereseffectivementutilesdansla chaıne et nonde la taille du bloc memoirealloue commele retourneraitsi-zeof() .

22.On dit aussiparfoisstructuresr ecursivesparabusdelangage.

24 DamienMercier Aide-memoire deLangage C 6 fevrier2000

maliste=(liste *)malloc(100*sizeof(liste));/* chainage des elements de la liste */for(i=0;i<99;i++) {

(maliste+i)->suivant=(maliste+i+1) ;(maliste+i)->valeur=i;

};(maliste+99)->valeur=99;(maliste+99)->suivant=NULL;

som=0;/* somme des elements de la liste *//* fonctionne par le chainage et non par les positions en memoire */for (temp=maliste; temp; temp=temp->suivant) {

som += temp->valeur;}printf("somme: %d\n",som);

exit(0);}

Dansla declarationd’une structureautoreferentielle,il n’est paspossibled’utiliser le type tliste defini par letypedef commeon le fait pour les declarationsde variablesdu main(), il estpossibleen revanched’utiliser le typestructurestruct liste encoursdedeclaration.

5.6 Les pointeurs de fonction

Il estparfoissouhaitablequ’unefonctiongeneriqueait besoinde pouvoir effectuerle memetraitementa peudechosespres.C’estparexemplele casd’unefonctiondetri generique,qui aurabesoind’unefonctiondecomparaison,differenteselonl’application23.

Pourpasserunefonctionen parametrea uneautrefonction, il existedespointeursde fonctions,qui sonten faitdespointeurscontenantl’adressememoirededebut dela fonction24. Afin quele compilateurconnaisselesargumentsdela fonctionpointee,ceux-cifont partiedela declarationdu pointeur. On auraparexemple:

#include <stdio.h>#include <stdlib.h>

/* fonction qui effectue la derivation numerique partielle *//* par difference finie d’une fonction de x et y selon x *//* fonc est le nom local de la fonction a deriver *//* x,y est le point de derivation et h est l’intervalle */float numderiv(float (*fonc) (float, float), float x, float y, float h) {

return (fonc(x+h,y)-fonc(x-h,y))/2/h;/* on pourrait aussi ecrire : *//* return ((*fonc)(x+h,y)-(*fonc)(x-h,y))/2/h; *//* mais attention aux parentheses ! */

}

/* une fonction de deux variables */float f1(float x, float y) {

return x*y*y;}/* La meme fonction inversee */float f2(float x, float y) {

return f1(y,x);}/* une autre fonction */

23.C’estcommecelaquefonctionnela fonctiondetri qsort() .24.Dansle casou la fonctiona ete declareeinline, c’estla versionsousformedefonctionstandardqui estutilisee.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 25

float f3(float x, float y) {return 3*x*x;

}

main() {float x,y;x=3.0; y=2.0;printf("x:%f y:%f f(x,y):%f df/dx(x,y):%f\n",x,y,f1(x,y),

numderiv(f1, x, y, 0.1));/* on pourrait aussi ecrire numderiv( &f1 , x, y, 0.1)); */

printf("x:%f y:%f f(x,y):%f df/dy(x,y):%f\n",x,y,f2(y,x),numderiv(f2, y, x, 0.1));

printf("x:%f y:%f f3(x,y):%f df3/dx(x,y):%f\n",x,y,f3(x,y),numderiv(f3, x, y, 0.1));

exit(0);}

Qui affiche:x:3.000000 y:2.000000 f(x,y):12.000000 df/dx(x,y):3.999996x:3.000000 y:2.000000 f(x,y):12.000000 df/dy(x,y):11.999994x:3.000000 y:2.000000 f3(x,y):27.000000 df3/dx(x,y):17.999982

Il estpossibledepasserunefonctionenargument(doncunpointeurdefonction)auneautrefonctionindiff erem-mentparf1 ou&f1 . Cecicarle compilateursaitqu’il s’agitnecessairementd’un pointeur, la fonctionn’etantpasunevariable.De la memefacon, lors desonutilisation, lessyntaxesfonc() et (*fonc) () sontequivalentes(noterlesparenthesesdansla deuxiemeecriture,necessairesdu fait desprioritesdesoperateurs).

Pourlesamateursdeprogrammesillisibles, il estpossibled’ecrirelesappelsdefonctionsnormauxdeplusieursfaconaussi(enutilisantgcc, cecin’estpasvalablesur touslescompilateurs): f1(y,x) estequivalenta (*f1)(y,x) , etmemea (* (* (&f1))) (y,x) .

6 Le preprocesseur

Lorsdela compilationd’un fichiersourceenC, il sederouleenfait plusieursoperationssuccessives.La premierephaseestunepassederemplacementtextuel uniquementet esteffectueepar le preprocesseur. Il estpossibledevoirle codesourceensortiedu preprocesseuravecla commandegcc -E .

Les lignes que le preprocesseurinterpretecommencentpar un dieze(#) eventuellementprecede de caracteresd’espacement.Les commmandesdu preprocesseurs’etendentchacunesur une ligne entiere et uneseule;la seulefacond’ecrireunecommandedupreprocesseursurplusieurslignesestd’empecherl’interpretationducaracteredefindeligne enle faisantprecederd’un caractere\ (tout a fait a la fin dela ligne).

Trois typesd’operationssonteffectueesparle preprocesseur: l’inclusion defichiers, la substitution desmacroset la compilation conditionnelle.

6.1 L’inclusion defichiers

La commande#include <nom de fichier> permetd’inclure le texte du fichier reference a la placedelacommande.Deuxsyntaxesexistentpourcettecommande: #include <toto.h> et #include "toto.h" quidifferentparlesrepertoiresdanslesquelsle preprocesseurvacherchertoto.h .On retiendraen general#include <stdio.h> pour les headers du systeme(le compilateurne va paschercherdansle repertoirecourant,maisuniquementdansles repertoiresstandardsdu systeme),et #include "toto.h"pourlesheadersduprojet,cettedernieresyntaxeforcantle compilateurachercherle fichierd’aborddansle repertoirecourant.

6.2 Les macros(#define)

Une macropermetun remplacementd’un mot particulierdanstout le texte qui suit. Par exemple,la definitionsuivanteremplacedanstoutela suitele mot test parprintf(”Ceci estun test� n”) :#define test printf("Ceci est un test\n");

26 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Il n’est paspossibledansla suite du codede redefinir de la memefacon test , il faut commencerpour cela parsupprimerla definition courantepar #undef test . Appliquer #undef a un identificateurinconnun’est pasuneerreur, c’estsimplementsanseffet.

Les macrospermettentegalementde definir desremplacementsplus intelligents,avec desargumentsvariables.Ainsi la fonctionMIN decriteprecedemment(paragraphesurlesoperateurs)peuts’ecriresousformedemacro:#define MIN(a,b) (a)>(b)?(b):(a)

ToutecrituredanslasuitedutextedeMIN(expr1,expr2) ferale remplacementtextuelenecrivantl’expressionderemplacementapresavoir substitue a a le texte deexpr1 et a b le texte deexpr2 . La presencedenombreusesparenthesesestchaudementrecommandeecar danscertainscasla priorite desoperationseffectueesdansla macropeutetresuperieurea celledesoperationsfaitesdanssesarguments.Par exemple,supposonsquel’on definisseunemacroPRODUITainsi:#define PRODUIT(a,b) a*bAlors uneinstancenoteePRODUIT(2+3, 7); donnera �������� c’est a dire 23, cequi n’estpeut-etrepasl’ef fetrecherche.. .

D’autresfonctionnalitesderemplacementplusfinessontpossibles,maissortentducadredecetaide-memoire.Le preprocesseurtient egalementa jour desmacrosspecialesqui contiennentla date,l’heure,le numerodela ligne

encourset le nomdefichier encours: __DATE__, __TIME__ , __LINE__ et __FILE__ , qui sontutilesdanslecasd’affichagedemessagesd’erreur.

6.3 Compilation conditionnelle

On souhaiteparfoiscompilerou noncertainespartiesd’un programme,parexemples’il doit fonctionnersurdesmachinesutilisantdessystemesd’expoitationdifferents,maisaussipour inclureou nondu codededeverminageparexemple.Pourcelale preprocesseurpermetd’inclure despartiesdecodeenfonctiondeconditions.La syntaxeest:

#if <condition><code C a compiler si la condition est vraie>

#endif

Lorsqu’unealternativeestpossible,on peutecrire:

#if <condition><code C a compiler si la condition est vraie>

#else<code C a compiler si la condition est fausse>

#endif

Dansle casd’alternativesmultiples,on ameme:

#if <condition 1><code C a compiler si la condition 1 est vraie>

#elif <condition 2><code C a compiler si la condition 1 est fausse et 2 vraie>

#else<code C a compiler si les deux conditions sont fausses>

#endif

LesconditionssontdesexpressionsC booleennesne faisantintervenir quedesidentificateursdu preprocesseur. Lesexpressionsde la forme defined(<identificateur>) sontremplaceespar 1 si l’identificateurestconnudupreprocesseuret par0 sinon.Commeil estfrequentd’ecrire#if defined(<id>) ou#if !defined(<id>) ,desformesabregeesexistentetsenotentrespectivement#ifdef <id> et #ifndef <id> .

Citonsdeuxautresutilisationsimportantesdesremplacementspar desmacros,qui sont la compilationavec ducodededeverminage(debug) optionnel,et la gestiondesvariablesglobales.Le petitmorceaudecodesuivanteffectueunappelaprintf() pourafficherunmessage,maisuniquementsi le programmeaetecompileendefinissantDEBUG.Ceci peut avoir ete fait dansun desfichiers header(.h) inclus systematiquement,ou bien par l’ajout de l’option-DDEBUG pourgccsurla lignedecompilation.

#include <stdio.h>

#ifdef DEBUG#define DEB(_x_) _x_#else

6 fevrier2000 Aide-memoire deLangage C DamienMercier 27

#define DEB(_x_)#endif

main() {DEB(printf("Ceci est un message de debug\n"));

}

La macroDEB estici remplacee,soit parcequi estentreparenthesessi DEBUG estdefini, soit par rien danslecascontraire.C’estpluscourtet pluslisible que:

main() {#ifdef DEBUG

printf("Ceci est un message de debug\n");#endif}

L’autreutilisation importanteconcerneles variablesglobales.En effet, celles-cidoivent etredeclareesdansUNSEUL fichier source(si possiblecelui qui contientla fonctionmain()), et doiventavoir unedeclarationprecedeedeextern danstouslesautressources.Cecisefait simplementendeclarantcettevariableavecunemacroEXT dansunfichier header(.h) inclusdanstouslessources.La macroestensuitedefiniecommevalantrien du tout si l’inclusionestfaitedansle fichier contenantle main(), et commeextern partoutailleurs.Voyonsunpetit exemple:

Ici un fichier general.h, inclusdansTOUSlessources:

/* EXT sera remplace par extern partout sauf si MAIN est defini */#ifdef MAIN# define EXT#else# define EXT extern#endif

EXT int monglob1;EXT char *glob2;

Voici le debut decalcul.c:

#include "general.h"

int trescomplique(int a) {return a+monglob1;

}

Et le debut demain.c:

#define MAIN#include "general.h"#include <stdio.h >

main() {monglob1=3;printf("Resultat: %d\n",trescomplique(2));

}

7 Fonctionsd’entr ee/sortie

De nombreusesfonctionsd’entree-sortieexistentdansla bibliothequestdio.h . Seulescertainessontdecritesdanscettepartie,le resteestpresente dansl’annexe.Unedescriptionplusdetailleedecesfonctionssetrouve a la findu manueldereferencedeKernighanet Ritchie,ou dansle manenligne sousUnix.

28 DamienMercier Aide-memoire deLangage C 6 fevrier2000

7.1 Le passaged’ar gumentsen ligne decommande

La fonctionmain() d’un programmepeutenfait prendredesarguments.La declarationcompleteest(lestypesdesargumentssontimposes):int main(int argc, char **argv)

Onecritaussifrequemment: int main(int argc, char *argv[]) qui alemeritederappelerqueargvestun tableau.Cesdeuxparametrescorrespondentaunombred’argumentsde la ligne decommandeencomptantlenomdel’executable(argc ) et a la listedecesargumentssousformedechaınesdecaracteres(argv[1] , argv[2] ,. . . , argv[argc-1] ). La premierechaıneargv[0] contientle nomd’appeldu programme.

Il estainsipossibledepasserdesargumentsenligne decommandea un programme.Cesargumentspeuventetreconvertisaveclesfonctionsdeconversiondela bibliothequestandard(#include <stdlib.h> : cf. Annexe):double atof(char *s);int atoi(char *s);long atol(char *s);

Ougraceauxfonctionsd’entreemiseenformequenousallonsvoir maintenant.

7.2 Entr ee/sortiesimples

Tout cequi suit estsubordonne a l’inclusion du header� stdio.h� qui declareles fonctionsd’entree-sortieainsiquela structureFILE . Lesdeuxsectionsqui suiventdonnentunapercu desfonctionsd’entree-sortiesanslesdetailler.Onsereporteraa l’annexequi suit pourdeplusamplesprecisions.

Les fonctionsd’entree-sortieoperentsur desflots (de type FILE), qui doivent avoir ete declaresau prealable.L’entreestandard,la sortiestandardet la sortied’erreursontautomatiquementouvertset senommentrespectivementstdin, stdoutet stderr25. Par defautl’entreestandardestle clavier, et lessortiessonta l’ ecran.Lesoperateursderedi-rectiondu shellpermettentneanmoinsd’alterercecienredirigeantcesaccesvers/depuisun fichier/autreprogramme.

Pourdesflots associesa desfichiers,il faut au prealableles ouvrir avec la fonction fopen(). Une bonnereglearespecterestquetout flot ouvertparun programmedoit etrefermeparfclose()desqu’il nesertplus.

Lesflots sontdesabstractionsqui permettentdenepasavoir a reprecisera chaqueutilisationd’un fichier touslesparametres: unefois le fichier ouvert, touteslesoperationsulterieuresfont referencea cefichier parle flot, cequi estbeaucoupplusrapidecar la bibliothequestandard(et aussile systemed’exploitation)retientl’ etatcourantdu fichier(positiondansle fichier, emplacementsur le disque...).Cetteabstractionpermetegalementde travailler surd’autresobjetssequentielsenutilisantlesmemesfonctions,c’estle casparexemplepourlestuyaux entreprocessus,pourlessocketsreseau...

Les fonctionsfr ead()et fwrite() permettentde lire desblocsdedonneesdansun flot sansaucuneinterpretation(Cf. Annexe).Si l’on souhaiteplutot lire unfichierligneparligne,il estpreferabled’utiliser fgets()qui offre l’avantagedes’arreterauxfins deligne (caractere’\n’ ), et garantittout dememequela longueurde la chaınedestockagenepeutpasetredepassee.

Dansles casou le but estde traiter lescaracteresun a un sansattendre,il faut utiliser getc() et putc() (ou leursequivalentsgetchar()etputchar() pourlesflotsd’entree-sortiestandards).La fonctionungetc()qui permetd’implan-tersimplementun look-ahead26 defacon simplepeutegalementrendreservice.

Lesfonctionsfopen(), fr ead(), fprintf() , fflush()... sontdesfonctionspresentesdansla bibliothequestandard,et sontdoncnormalementdisponiblessur tousles systemesd’exploitation. Cesfonctionssont ecritesen C et precompileesdansun fichier d’archive qui formela bibliothequestandard,et qui estajoute automatiquementlors dela compilation.Ecrire fopen() esten fait un simpleappelde fonction verscettebibliotheque,dont le codeexecutablefait partieduprogramme.A sontour, cesfonctions(fopen()parexemple)utilisentdesservicesfournisparle systemed’exploitationpoureffectuerleur tache.Cesservicessontsollicitesvia un ou plusieursappelssystemequi demandentaunoyau dusystemed’exploitationd’ouvrir le fichier voulu. SousUnix l’appel systeme(dont l’utilisation estsimilaire a un appelde fonction)utilise ainsiestopen(), qui retourneun entierappele descripteur de fichier Unix. Cettevaleurderetoureststockeedansl’objet FILE afin d’en disposerpour les manipulationsulterieures.QuelquesautresappelssystemeconcernantlesfichierssousUnix sontread(), write() , close()...Il estfortementrecommandedenepasmelangerpourunmemeflot desappelsauxfonctionsdela bibliothequestandardetdesappelssystemeUnix caril n’y auraitdanscecasaucunegarantiequel’ordre desoperationssoit respecte(acausedestamponsenmemoiremaintenusparla bibliothequestandard).

25.En fait, cettepropriete n’est assureequepour un systemed’exploitation Unix, memesi la plupartdescompilateursC fonctionnantdansd’autresenvironnementstententdesimulercecomportement.

26.Litt eralementregarder enavant, c’estunemethodededecisiondu typedelexemequi suit a partir dela lecturedu premiercaractereunique-ment.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 29

7.3 Entr ees/sortiesavecformat : fprintf(), fscanf()

Pourobtenirdesresultatsjoliment mis en forme, la commandea utiliser est fprintf( flot, format, variables...).Lorsqueflot est la sortie standard,un raccourciexiste: printf( format, variables...). Le format estunechaıne decaracteresqui decrit la facon d’afficherlesvariablesqui suivent; parexempleprintf("x=%d y=%f\n",x,y);affichex= suivi de la valeurde la variableentierex, puisun espacepuisy= suivi de la valeurde la variableflottantey et un retourchariot.La fonction printf estune fonction particulierequi prendun nombrevariabled’arguments.Lescodesa utiliser dansle formatindiquentle typedela variableet sontpresentesenannexe.Ainsi pourafficherunnombrecomplexe,on ecriraparexempleprintf("z=%f+i%f\n",Re(z),Im(z)); .

La valeurderetourde fprintf() estle nombre de caractereseffectivementecrits,ou unevaleurnegative encasd’erreur.

La lecturedevaleursefait parla fonctionfscanf(flot, format, adressesdesvariables...). Le principeestsimilaireafprintf() , exceptequelesadressesdesvariablesdoiventetredonneesafinquefscanf()puisseallermodifierleurvaleur.Lorsqueflot estl’entreestandard,on peututiliser scanf(format, adressesdesvariables...). Ainsi pour lire enentreeunevariableflottantefloat x; suivied’unechaınedecaractereschar cha[1024];,onecrirascanf("%f%s",&x, cha);La variablex estpasseeparadresse,et la chaıneaussipuisqu’il s’agit d’un pointeur, doncd’uneadressememoire.

La fonctionfscanf() retournele nombredechampsqu’elleapulire, oula constantespecialeEOFencasd’erreurou defin defichier.

Les caracteresautresquedescaracteresde formatageet les espacespresentsdansle format de scanf() doivent cor-respondreexactementaux caracteresentresau clavier. Il faut en particulier eviter de mettreun \n dansce format.Lescaracteresd’espacementsontconsideresparfscanf()commedesseparateursdechamps.Il n’estdoncpaspossiblederecupererd’un coupunechaınedecaracterescomportantdesblancsaveccettefonction.C’estpourquoion utiliseraplutot char *fgets(char *s, int n, FILE *f) qui lit unelignejusqu’auretourchariotoujusqu’acequ’ily ait n caracteresetstocke le resultatdanss (elle retournes egalements’il n’y apaseud’erreur).

Il ne fautpasperdredevuequele systemedefichiersd’Unix estbufferise.Ainsi pour l’entreestandard,celle-cin’estpriseencomptequeligneparligneapresunretourchariot27. Dememepourla sortiestandard28. Lorsqu’onecritdansun fichier, ou si la sortiestandardestredirigee,la bufferisationestencoreplus importantepuisquela taille dutamponpeutatteindreplusieurskilo-octets.Pourforcerl’ ecriture,on utilise fflush(). Cettefonctionestutile, carsi unprogrammen’arrivepasa sonterme(arret intempestifdela machine,ou erreura l’executionparexemple)lesbufferssontirremediablementperdus.

Enfin la fonctionfclose()permetdefermerun fichier, envidantauparavantsonbuffer.

8 Complements: la biblioth equestandard et quelquesfonctionsannexes

La bibliothequestandardne fait paspartie a proprementparler du langageC mais elle a ete standardiseeparla normeANSI et offre doncun ensemblede declarationsde fonctions,de declarationsde typeset de macrosquisontcommunesa tous les compilateursqui respectentla norme,quel quesoit le systemed’exploitation.Quelquesexemplespresentesici sontneanmoinsdesextensionsdecettebibliothequestandardspecifiquesaumondeUnix. Denombreusesfonctionsdela bibliothequestandardreposentsurdesappelssystemesUnix qui leur ressemblent,commeopen(), close(), read()ou lseek()parexemple.Si la portabilite versdesenvironnementsnon-unixn’estpasdemise,il pourraetreinteressantdanscertainscasd’utiliser plutot cesdernieresfonctions.

Touteslesdeclarationsdela bibliothequestandardfigurentdansdesfichiersinclude:� assert.h� � float.h� � math.h� � stdarg.h� � stdlib.h �� ctype.h� � limits.h � � setjmp.h� � stddef.h� � string.h�� errno.h� � locale.h� � signal.h� � stdio.h� � time.h�Cesfichiersdoiventetreinclusavant touteutilisationd’unefonctionde la bibliothequeparunedirective du type

#include <fichier_include.h> . Ils peuventetreinclusdansun ordrequelconque,voire plusieursfois dans

27. Il estpossible,maisceciestspecifiqueUnix dereparametrerle terminalafinderecevoir lescaracteresunaunsansattendreunretourchariot.28.La un fflush() permetde forcer l’ ecrituren’importe quand.Il resteneanmoinspreferabled’utiliser stderr pour les sortiesd’erreursnon-

bufferisees.

30 DamienMercier Aide-memoire deLangage C 6 fevrier2000

un memesource.Ils contiennentdesdeclarationsdefonctionsquele compilateurconnaıt pardefautpour la plupart,excepte pour � math.h� qui declaredesfonctionsde la bibliothequemathematiquequ’il faut indiquera l’ editiondelien defacon explicite (Voir 2).

Lesidentificateursmasquesa l’utilisateur a l’int erieurdecettebibliothequeont desnomscommenc¸antparun ca-racteredesoulignement_. Il estdoncrecommanded’eviterd’utiliser cetypededenominationpoureviterd’eventuelsconflits.

Seuleslesfonctionsprincipales sontpr esenteesici.Pourdesinformationsplusdetaillees,onsereporteraaupagesdemanuelenlignesousUnix accessiblesparman

fgetsparexemplepour la fonction fgets(). Mais unefonctioncommeopen()estegalementle nomd’unecommandeUnix aussimanopenneretournerapasla pagevoulue.Danscecas,onpreciserala sectiondumanuelcorrespondante,ici la section2 (pourlesappelssysteme)ou3 (pourlesfonctionsdela bibliotheque).Cecis’ecritman 2 openouman3 fprintf .

8.1 � stdio.h� : entrees-sorties

Il s’agit de la partie la plus importantede la bibliotheque.Sanscelaun programmene peutafficher ou lire desdonneesdefacon portable.La sourceou la destinationdesdonneesestdecriteparun objetdetypeFILE, appeleflot.Ce type structure, dont il n’est pasutile de connaıtre les differentschamps(ils peuvent d’ailleurs differerentrelesversionsdela bibliotheque)estassocie aunfichier surdisqueou a unautreperipheriquecommele clavier ou l’ ecran.Il existedesflots binairesetdesflotsdetexte,maissousUnix ceux-cisontidentiques29.

Un flot est associe a un fichier par ouverture,ceci retourneun pointeursur une structureFILE. A la fin desoperationssurle flot, il fautle fermer.

Au debut de l’executiondu programme,trois flots speciaux,nommesstdinpour l’entreestandard,stdoutpour lasortiestandardetstderrpourla sortied’erreursontdejaouverts.En l’absenced’operationsspeciales,stdincorrespondauclavier, stdoutet stderrcorrespondenta l’ ecran.

Ouvertur e-fermeturede fichiers

FILE *fopen(const char *nomfich, const char *mode)Ouvrele fichier indique (le nom estabsoluou relatif au repertoirecourant,maissansremplacementdescaracteresspeciauxcomme˜ ) et retourneun flot, ou NULL en casd’erreur. L’argumentmode est unechaıne de caracteresparmi:

r lectureseule,la lecturecommenceaudebut dufichier.w ecritureseule.Si le fichier n’existait pas,il estcree; s’il existait, il estecrase.a (append) aimilaireaw maisecrit a la fin dufichier sansl’ ecrasers’il existait.

r+ lectureet ecriture.Le flot estpositionneaudebut du fichier.w+ Le fichierestcree(ou ecrases’il existait),etouvertenlectureet ecriture; le flot estpositionne

audebut.a+ similairea r+ , maisle flot estinitialementpositionne a la fin dufichier.

Dansle casdesmodeslecture-ecriture,il fautappelerfflush() ouunefonctiondedeplacemententrelesoperationsdelectureet d’ecriture.L’ajout deb a la fin du modeindiqueun fichier binaire,c’est-a-diresansconversionautoma-tiquedesfins deligne (celan’a aucuneffet sousUnix, voir la note29).

FILE *freopen(const char *nomfich, const char *mode, FILE *flot)Cettefonctionserta associerauxflotspredefinisstdin, stdoutou stderrun fichier.

int fflush(FILE *flot)Cettefonctionn’estaappelerquesurun flot desortie(oud’entree-sortie).Elle provoquel’ ecrituredesdonneesmisesenmemoiretampon.Elle retournezeroenl’absenced’erreur, EOFsinon.

int fclose(FILE *flot)Provoquel’ ecrituredesdonneesenattente,puisfermele flot. La valeurderetourestzeroenl’absenced’erreur, EOFsinon.

FILE *fdopen(int fd, const char *mode)Ouvreun flot correspondantaudescripteurdefichier Unix fd. Necessiteun descripteurdefichier valide(parexemple

29.SousDOS,lesflots texte convertissentlessequencesCR-LF enLF seul(codes� r � n en � n seul),sousMacOS,ils convertissentle CR enLF(code � r en � n), sousUnix, ils convertissentlesLF enLF !

6 fevrier2000 Aide-memoire deLangage C DamienMercier 31

issudeopen()). Le descripteurn’estpasduplique,aussiil fautauchoixsoit terminerparclose(fd), soitparfclose(flot),maissurtoutpaslesdeux.Ne fait paspartiedela normeANSI.

int fileno( FILE *flot)Retournel’entier descripteurdefichier Unix associeauflot. Ne fait paspartiedela normeANSI.

Positionnementet erreurs

int fseek(FILE *flot, long decalage, int origine)Positionnela tetedelecturedansle flot flot. L’entieroriginepeutvaloir SEEKSET, SEEKCURouSEEKENDselonquela positionestdonneerespectivementa partir du debut du fichier, de la positioncourante,ou de la fin. decalagerepresentele decalagedemandeennombred’octets(attentionausigne,unevaleurnegativefaisantrevenirenarriere).

fseek()retourneunevaleurnonnulle encasd’erreur, zeroencasdesucces.

long ftell(FILE *flot)Donnela valeurdela positioncourantedansle fichier (ennombred’octetsdepuisle debut dufichier),ou la valeur-1L(-1 sousformede long) encasd’erreur.

void rewind(FILE *flot)Retourneaudebut du fichier. Equivalenta (void)fseek(flot,0L, SEEK SET).

int feof(FILE *flot)Retourneunevaleurnonnulle si l’indicateurdefin defichierestactif, c’est-a-diresi la derniereoperationsurle flot aatteintla fin du fichier.

int ferror(FILE *flot)Retourneunevaleurnonnulle si l’indicateurd’erreurduflot estactif.

Toutesles fonctionsqui prennenten argumentun flot (de type FILE * ) necessitentquece flot soit valide. Enparticulier, il ne fautpasfaire f=fopen(...) puisappelerimmediatementferror(f) , car f peutvaloir NULLsi l’ouverturedufichier a echoue.la solutionestalors:

FILE *f;

f=fopen("mon_fichier","r");if (f==NULL) {

perror("Impossible d’ouvrir le fichier\n");exit(EXIT_FAILURE);

}

void clearerr(FILE *flot)Remetazerolesindicateursdefin defichier et d’erreur.

void perror(const char *s)Affichesurstderr la chaınes et un messaged’erreurcorrespondanta l’entier contenudansla variableglobaleerrno,doncissudela derniereerreurrencontree.

perror(s) estequivalenta (void)fprintf(stderr, "%s : %s\n", strerror(errno) , s)

int fgetpos(FILE flot, fpos t *pos)int fsetpos(FILE *flot, fpos t *pos)Cesontd’autresfonctionspermettantderelire la positiondansle fichier (commeftell(flot) ) ou del’imposer(commefseek(flot,SEEK SET)). Cettepositioneststockeedansun objet de type fpos t (sousUnix, c’est un long, maiscepeutetreunestructurecomplexesurd’autressystemesd’exploitation).

Entr ee-sortiedir ecte

size t est un type (correspondanta un entier) qui exprime une taille memoire(en octet, issuepar exempledesizeof(), commepourmalloc()) ou un nombred’elements.

size t fread(void *ptr, size t size, size t nobj, FILE *flot)Lit sur le flot nobj objetsdetaille sizeet lesecrit a l’emplacementmemoirepointe parptr. La valeurderetourestlenombred’argumentslus avecsucces,qui peutetreinferieura nobj. Pourdeterminers’il y a euerreurou si la fin dufichier a ete atteinte,il faututiliser feof() ou ferr or().

32 DamienMercier Aide-memoire deLangage C 6 fevrier2000

size t fwrite(const void *ptr, size t size, size t nobj, FILE *flot)Ecrit surle flot nobjobjetsdetaille sizepris a l’emplacementpointeparptr. Retournele nombred’objetsecrits.

Entr ee-sortiede caracteres

int fgetc(FILE *flot)Lit un caracteresur le flot (unsignedchar converti en int) et le retourne.RetourneEOF en casde fin de fichier oud’erreur(EOFestuneconstanteentieredefinieparstdio.h, valantgeneralement-1).

int fputc(int c, FILE *flot)Ecrit le caracterec (converti enunsignedchar) surle flot. RetournececaractereouEOF encasd’erreur.

int getc(FILE *flot)Equivalenta fgetc(), maiseventuellementimplantesousformedemacro.Plusefficacequefgetcengeneral.Attention,l’ evaluationdeflot nedoit provoquerd’effet debord(utiliserunevariablepourflot et nonle retourd’unefonction).

int putc(int c, FILE *flot)Equivalenta fputc(). Memeremarquequepourgetc().

int getchar(void)Equivalenta getc(stdin).

int putchar(int c)Equivalenta putc(c, stdout).

int ungetc(int c, FILE *flot)Remetle caracterec (converti enunsignedchar) surle flot, ou il seraretrouvea la prochainelecture.Un seulcaracterepeutetreainsiremis,et celanepeutpasetreEOF. Retournele caractereenquestionou EOFencasd’erreur.

char *fgets(char *s, int n, FILE *flot)Lit uneligne completedecaracteres(jusqu’aucaracteredefin de ligne compris)d’au plus ����� caractereset placecettechaıneapartirdela casememoirepointeepars. Si uncaracteredefin deligneestlu, il eststockedansla chaıne.Le caractere’\0’ estalorsajoute a la chaıneprecedemmentlue. Retournes si tout s’estbienpasse, ou bienNULLencasd’erreurou si la fin du fichier estatteintesansaucuncaracteredisponiblele precedant.

int fputs(char *s, FILE *flot)Ecrit la chaınedecaracteresssurle flot (n’ecritpasle caractere’\0’ defin dechaıne).Retourneunevaleurpositiveou nulle,ou bienEOFencasd’erreur.

Il existeunefonctiongets()similairea fgets(), maissonusageestfortementdeconseille.

Entr ee-sortiemisesen forme

int fprintf(FILE *flot, const char *format, ...)Estla commandedesortiemiseenforme.Il s’agitd’unefonctionanombrevariabled’arguments(Voir 8.8).La chaıneformatdecrit le textea ecrire,danslequeldessuitesdecaracteresspeciauxcommenc¸antpar%sontremplaceesparlesvaleursdesargumentsqui suiventdansl’ordre. La valeurentierederetourest le nombre decaracteresecrits, ou encasd’erreurun nombrenegatif.

La chaıne de caracteresformat contientdescaracteresordinaires(sans%) qui sontcopies tels quelssur le flotde sortie,et desdirectivesde conversiondont chacunepeutprovoquerla conversiondansl’ordre d’un argumentdefprintf() suivantla chaınedeformat.

Chaquedirective deconversioncommencepar le caractere%et setermineparun caracteredeconversionparmiceuxpresentesdansle tableauqui suit.Entrele %et le caracteredeconversionpeuventapparaıtredansl’ordre:

– Desdrapeaux,parmi:

# formatdesortiealternatif.– cadragea gauchedu champ.+ ajoutsystematiquedu signeauxnombres.

’ ’ (espace)ajoutd’un caracterepourle signedesnombres,soit l’espacepourlesvaleurspositivesou le signe’-’ pourlesvaleursnegatives.

0 (zero)completele debut duchamppardeszerosaulieu d’espacespourlesnombres.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 33

– Un nombreprecisantla largeurminimaledu champd’impressionennombredecaracteres.

– Uneprecisionsousla formed’un point suivi d’un nombre(la valeurde cetteprecisionestconsidereecommezero en l’absencede ce champ).Il s’agit du nombremaximal de caracteresa imprimer pour unechaıne decaracteres,ou du nombreminimal dechiffrespour lesconversionsd, i, o, u, x et X. Pourlesconversionse, Eet f celadonnele nombrede chiffresapresle point decimal,et sinoncelacorrespondau nombremaximaldechiffressignificatifspourlesconversionsg et G.

– Enfin unelettreh, l ou L qui modifiele typedel’argumentconverti. h specifieun argumentshort, l specifieunargumentlong, etL unargumentlongdouble(ou long longpourlesconversionsentieres,bienquececinefassepaspartiedela normeANSI).

Voici enfinlescaracteresdeconversion:

d, i, o, u, x, X Varianted’int. d:decimal.u:decimalnonsigne.o:octal.x:hexadecimalnonsigneutilisantabc-def. X:hexadecimalnonsigneutilisantABCDEF.

e,E doubleecrit endecimalsousla forme [-]m.ddddddEdd . La precisiondonnele nombredechiffre apresle pointdela mantisse,la valeurpardefautest6. eutilise la lettreeetE utiliseE.

f doubleecrit sousla forme [-]ddd.ddd . La precisiondonnele nombrede chiffre apreslepointdecimal,savaleurpardefautest6. Si la precisionvaut0, le pointdecimalestsupprime.

g, G doubleecrit endecimalcommeparuneconversionpar f oue selonla valeurdel’argument.c int converti enunsignedchar etaffichecommeun caractereASCII.s char * . Chaınedecaracteres.p void * . Pointeurecrit enhexadecimal(commeavec%#lx ).n int * . Neconvertit pasd’argument,maisecritdansl’argumentle nombredecaracteresaffiches

jusqu’apresent.% Affichesimplementun %sansaucuneconversion.

Chaquedir ectivede conversiondoit correspondreexactementa un argumentde type correctdansle memeordr e.

Leserreurssurlestypesdesargumentsou leurnombrenesontgeneralementpasdetectesparle compilateuretpeuventprovoquerdesresultatssurprenantsa l’execution.

int fscanf(FILE *flot, const char *format, ...)Est la commanded’entreemiseen forme. Il s’agit aussid’une fonction a nombrevariabled’arguments.La chaıneformat decrit les objetsa lire et leur type, et ceux-ci sont stockesdansles argumentsqui suivent qui doiventetreobligatoirementdespointeurs. La valeurentierede retourest le nombred’elementsd’entreecorrectementassignes(comprisentre0 et le nombrededirectivesdeconversion).Si la fin defichier estatteinteavanttoutelecture,la valeurEOF estrenvoyee.Si la fin de fichier estatteinteen coursde lecture,la fonction retournele nombred’elementslussanserreur.

La chaıne de caracteresformat contientdescaracteresordinaires(sans%) qui doivent correspondreexactementauxcaractereslussurle flot d’entree(excepteslesespaceset lestabulationsqui sontignores).Elle contientegalementdesdirectivesdeconversionformeesdansl’ordre par:

– %,

– un caracterefacultatif ’*’ , qui, lorsqu’il estpresent,empechel’af fectationdela conversiona un argument(lechampestlu et savaleurignoree,aucunpointeurn’estutilise danslesargumentsdela fonction),

– uncaracterefacultatifh, l ou L qui specifieunevariantedetaille detype(voir ci-dessous),

– uncaracteredeconversionparmiceuxpresentesdansle tableauqui suit:

34 DamienMercier Aide-memoire deLangage C 6 fevrier2000

d Varianted’int * , lu sousformedecimale.i Varianted’int * , la lectureesten octal si l’entier commencepar 0, en hexadecimals’il com-

mencepar0x ou 0X, endecimalsinon.o Varianted’int * , lu sousformeoctale,qu’il commenceou nonparun 0.u Varianted’unsignedint * , lu sousformedecimale.x Varianted’unsignedint * , lu sousformehexadecimale.

f, e,g float * (ou double* ). Lestroiscaracteressontequivalents.c char * . Lit lescaracteressuivantset lesecrit apartirdel’adresseindiqueejusqu’ala largeurdu

champsi celle-ciestprecisee.En l’absencedelargeurdechamp,lit 1 caractere.N’ajoutepasde ’\0’ . Lescaracteresd’espacementsontlus commedescaracteresnormauxet nesontpassautes.

s char * . Chaıne de caracteres lue jusqu’au prochaincaractere d’espacement,en s’arretanteventuellementa la largeurdu champsi elle estprecisee.Ajoute un ’\0’ a la fin.

p void * . Pointeurecrit enhexadecimal.n int * . Ne convertit pasde caracteres,maisecrit dansl’argumentle nombrede caractereslus

jusqu’apresent.Necomptepasdansle nombred’objetsconvertisretournepar fscanf().����� �] char * . La plus longuechaıne de caracterenon vide composeeexclusivementde caracteres

figurantentrelescrochets.Un ’\0’ estajoutea la fin. Pourinclure ! danscetensemble,il fautle mettreenpremier

� ! � ��� ! .�#"$��� �] char * . La pluslonguechaınedecaracterenonvidecomposeeexclusivementdecaracteresNE

figurantPAS entrelescrochets.Un ’\0’ estajoute a la fin. Pourinclure ! danscetensemble,il fautle mettreenpremier

�#" ! ��� � ! .% Lit le caractere%. Ne realiseaucuneaffectation.

Lesvariantesdetaille detypesontpluscompletesquecellespour fprintf() : h preciseun shortet l un long pourlesconversionsd, i, n, o, u, x. l preciseun doubleet L un long doublepour lesconversionse, f, g. Ainsi pour lire undoubleon utilisescanf{"%lg",&d) maispourl’imprimer on utilise printf("%g",d) .

Un champenentreeestdefini commeunechaınedecaracteresdifferentsdescaracteresd’espacement; il s’etendsoit jusqu’aucaractered’espacementsuivant,soit jusqu’a cequela largeurdu champsoit atteintesi elle estprecisee.Enparticulier, scanf()peutlire au-deladeslimitesdelignessi necessaire,le caracteredefin deligneetantuncaracterecommelesautres.

Chaque dir ective de conversion doit correspondre exactementa un pointeur vers un argument de typecorrectdansle memeordr e.

Memeremarquequepourfprintf() . Deplus,si lespointeursdedestinationn’ont pasle bontype(oupireencores’il nesontmemepasdespointeurs),le resultata l’executionrisqued’etrederoutant...

int printf(const char *format, ...)Estequivalenta fprintf(stdout, format, ...).

int scanf(const char *format, ...)Estequivalenta fscanf(stdin, format, ...).

int sprintf(char *s, const char *format, ...)Estsimilairea fprintf() exceptequel’ ecrituresefait dansla chaınedecaracteressplutot quedansun flux. Attention,la taille dela chaınesdoit etresuffisantepourstocker le resultat(y comprisle derniercaractere’\0’ invisibledefindechaıne).Dansle cascontraire,on risqued’avoir deserreurssurprenantesa l’execution.

int sscanf(char *s, const char *format, ...)Estsimilairea fscanf()exceptequela lecturesefait dansla chaınedecaracteressplutot quedansun flux.

8.2 � ctype.h� : testsdecaracteres

Cesfonctionsretournentunevaleurnonnullesi l’argumentremplit la condition,etzerosinon.Toutescesfonctionsont commeprototypeint isalnum(int c) , et c, bienqu’etantun entierdoit contenirunevaleurrepresentable

6 fevrier2000 Aide-memoire deLangage C DamienMercier 35

commeun unsignedchar.

isalnum() isalpha()ou isdigit() estvrai.isalpha() isupper()ou islower()estvrai.iscntrl() caracteredecontrole.isgraph() caractereimprimablesaufl’espace.islower() lettreminuscule.isprint() caractereimprimabley comprisl’espace.ispunct() caractereimprimabledifferentdel’espace,deslettresetchiffres.isspace() espace,sautdepage,deligne, retourchariot,tabulation.isupper() lettremajuscule.

isxdigit() chiffre hexadecimal.

8.3 � string.h � : chaınesdecaractereset blocsmemoire

Chaınesde caracteres

char *strcpy(char *s, const char *ct)Copiela chaınect, y comprisle caractere’\0’ dansle chaınes, retournes.

char *strncpy(char *s, const char *ct, size t n)Copieauplusn caracteresdect danss, encompletantpardes’\0’ si ct comportemoinsden caracteres.

char *strcat(char *s, const char *ct)Concatenect a la suitedes, retournes.

char *strncat(char *s, const char *ct, size t n)Concateneauplusn caracteresdect a la suitedes, terminela chaıneresultatpar ’\0’ , retournes.

char *strcmp(const char *cs, const char *ct)Comparelexicographiquementcset ct. Retourneunevaleurnegativesi cs

�ct, nulle si cs% ct, positivesinon.

char *strncmp(char *s, const char *ct, size t n)Commestrcmp() maislimite la comparaisonauxn premierscaracteres.

char *strchr(char *s, int c)Retourneun pointeursurla premiereoccurrencedec (converti enchar) danscs, ouNULLsi il n’y ena aucune.

char *strrchr(char *s, int c)Commestrchr maispourla derniereoccurrence.

char *strstr(const char *cs,const char *ct)Retourneun pointeursurla premiereoccurrencedela chaınect danscs, ouNULLsi il n’y ena aucune.

size t strlen(const char *cs)Retournela longueurdecs, sanscompterle caracteredeterminaison’\0’ .

char *strerror(int n)Retourneun pointeursurla chaınecorrespondanta l’erreur n.

char *strtok(char *s, const char *ct)Decompositiondesenlexemesseparespardescaracteresdect.

Le premierappelala fonctionsefait enprecisantdanss la chaınedecaracteresadecomposer. Il retournelepremierlexemedescomposedecaracteresn’appartenantpasact, et remplacepar ’\0’ le caracterequi suit celexeme.

Chaqueappelulterieurastrtok() avecNULLcommepremierargumentretournealorsle lexemesuivantdesselonle memeprincipe(le pointeursurla chaıneestmemorised’un appelausuivant).La fonctionretourneNULLlorsqu’ellenetrouveplusdelexeme.

Cettefonction,d’usagepeuorthodoxe (utilisantdesvariableslocalesstatiques...)estextremementefficacecarelle estgeneralementecritedirectementenassembleur.

36 DamienMercier Aide-memoire deLangage C 6 fevrier2000

Blocsde memoire

void *memcpy(void *s, const void *ct, size t n)Copien octetsdect dansset retournes. Attention,leszonesmanipuleesnedoiventpassechevaucher.

void *memmove(void *s, const void *ct, size t n)Memerolequela fonctionmemcpy(), maisfonctionneegalementpourdeszonesqui sechevauchent.memmove()estpluslentequememcpy() lorsqueleszonesnesechevauchentpas.

int memcmp(const void *cs, const void *ct, size t n)Compareles zonesmemoirepointeespar cs et ct a concurrencede n octets.Les valeursde retoursuivent la memeconventionquepourstrcmp().

void *memset(void *s, int c, size t n)Ecrit l’octet c (unentierconvertit enchar) danslesn premiersoctetsdela zonepointeepars. Retournes.

8.4 � math.h � : fonctionsmathematiques

La bibliothequecorrespondanta cesfonctionsn’estpasajouteeautomatiquementpar le compilateuret doit doncetrepreciseelorsdel’ editiondeliensparl’option -lm.

Lorsqu’unefonctiondevrait retournerunevaleursuperieureaumaximumrepresentablesousla formed’un double,la valeurretourneeestHUGE VAL et la variableglobaled’erreurerrno recoit la valeurERANGE. Si les argumentssontendehorsdudomainededefinitiondela fonction,errno recoit EDOMet la valeurderetourestnonsignificative.Afin depouvoir testerceserreurs,il fautaussiinclure � errno.h� .

Toutesles fonctionstrigonometriquesprennentleur argumentou retournentleur resultaten radians.Les valeursderetoursonttoutesdesdouble, ainsiquelesargumentsdesfonctionsdu tableausuivant:

sin() sinus.cos() cosinus.tan() tangente.

asin() arcsinus.acos() arccosinus.atan() arctangente(dans

� �'&)(� �* &)(+ ,! ).atan2(y,x) pseudoarctangentede -.(0/ , tenantcomptedessignes,dans

� �'&1* &2! .sinh() sinushyperbolique.cosh() cosinushyperbolique.tanh() tangentehyperbolique.exp() exponentielle.log() logarithmeneperien.

log10() logarithmeabase10.pow(x,y) / a la puissance- . Attentionaudomaine: ( /3��4 ) ou ( /5%�4 , -6�74 ) ou ( / � 4 et - entier).

sqrt() racinecarree.floor() Partieentiereexprimeeendouble.ceil() Partieentiereplus1 exprimeeendouble.fabs() Valeurabsolue.

Pourobtenirla partieentiered’un float f sousla formed’un entier, on utilise le transtypageen ecrivantparexemple:(int)floor( (double)f ) .

8.5 � stdlib.h � : fonctionsutilitair esdiverses

double atof(const char *s)Convertit senun double.

int atoi(const char *s)Convertit senun int.

6 fevrier2000 Aide-memoire deLangage C DamienMercier 37

long atol(const char *s)Convertit senun long.

void srand(unsigned int graine)Donnegrainecommenouvelleamorcedu generateurpseudo-aleatoire.L’amorcepardefautvaut1.

int rand(void)Retourneun entierpseudo-aleatoirecomprisentre0 et RAND MAX, qui vautauminimum32767.

void *calloc(size t nobj, size t taille)Allocation d’unezonememoirecorrespondanta un tableaudenobj de taille taille. Retourneun pointeursur la zoneou NULLencasd’erreur. La memoirealloueeestinitialiseepardeszeros.

void *malloc(size t taille)Allocation d’une zonememoirede taille taille (issude sizeof()par exemple).Retourneun pointeursur la zoneouNULLencasd’erreur. La memoirealloueen’estpasinitialisee.

void *realloc(void *p, size t taille)Changeen taille la taille del’objet pointeparp. Si la nouvelle taille estpluspetitequel’ancienne,seulle debut delazoneestconserve. Si la nouvelle taille estplus grande,le contenude l’objet estconserve et la zonesupplementairen’estpasinitialisee.Encasd’echec,realloc()retourneunpointeursurlenouvelespacememoire,qui peutetredifferentdel’ancien,ou bienNULLencasd’erreuretdanscecasle contenupointeparp n’estpasmodifie.

Si p vautNULL lors del’appel, le fonctionnementestequivalenta malloc(taille).

void free(void *p)Liberel’espacememoirepointe parp. Ne fait rien si p vautNULL . p doit avoir ete alloue parcalloc(), malloc() ourealloc().

void exit(int status)Provoquel’arret du programme.Les fonctionsatexit() sontappeleesdansl’ordre inversede leur enregistrement,lesflot restantouvertssontfermes.La valeurdestatusestretourne a l’appelant30. Unevaleurnulle destatusindiquequele programmes’esttermineavecsucces.Onpeututiliser lesvaleursEXIT SUCCESSetEXIT FAILUREpourindiquerla reussiteou l’ echec.

void abort(void)Provoqueun arret anormalduprogramme.

int atexit(void (*fcn)(void))Enregistrequela fonctionfcn() devra etreappeleelorsdel’arretduprogramme.Retourneunevaleurnonnulleencasd’erreur.

int system(const char *s)SousUnix provoquel’ evaluationde la chaınes dansun Bourne-shell(sh). La valeurderetourestla valeurderetourde la commande,ou bien127ou -1 encasd’erreur. L’appelsystem(NULL) retournezerosi la commanden’estpasutilisable.

char *getenv(const char *nom)Recuperela declarationdela variabled’environnementdontle nomestnom. La valeurderetourestun pointeurversunechaınedu typenom= valeur.

void qsort(void *base, size t n, size t taille, 8int (*comp) (const void *, const void *))Il s’agitd’unefonctiondetri (parl’algorithmeQuicksort)dutableau9;:�<>= � 4+! � � 9;:�<?= � �@�A�B! dontlesobjetssontdetailletaille. La fonction de comparaisoncomp(x,y) utiliseedoit retournerun entierplus grandquezero si /C�D- , nul si/E%F%�- et negatifsinon.

void *bsearch(const void *key, const void *base, size t n, 8size t taille, int (*comp) (const void *, const void *))Cettefonctionrechercheparmi 9;:�<?= � 40! ��� 9;:�<>= � �G�H�B! (objetsdetaille taille triesparordrecroissantpourla fonctiondecomparaisonfournie),un objets’identifianta la cle *key. La valeurderetourestun pointeursur l’ elementidentiquea *key, ou NULLs’il n’en existeaucun.La fonctiondecomparaisoncomp() utiliseedoit obeir auxmemesreglesquepourqsort().

30.SousUnix si le programmea ete lance depuisunshellcshou tcsh,la valeurdestatuseststockeedansla variabledushelldememenom.

38 DamienMercier Aide-memoire deLangage C 6 fevrier2000

int abs(int n)Valeurabsolued’un elementdetype int.

long labs(long l)Valeurabsolued’un elementdetype long. Pourlesflottants,voir fabs()dans� math.h� .

8.6 � assert.h� : verifications a l’execution

Il s’agit de la declarationd’une macroassertpermettantde verifier desconditionslors de l’execution.On ecritpourceladansle corpsduprogramme:

assert( <expression> );

Lorsdel’execution,si l’ evaluationde<expression> donnezero(expressionfausse)la macroenvoiesurstderrunmessagedonnantl’expression,le fichiersourceet la ligneduproblemeetarretele programmeenappelantabort().

Si NDEBUG estdefini avantl’inclusion de � assert.h� , la macroassertn’a aucuneffet.

8.7 � limits.h � , � float.h � : constanteslimites� limits.h �CHAR BIT nombredebits parcaractere

CHAR MIN, CHAR MAX valeursmin et maxd’un charSCHAR MIN, SCHAR MAX valeursmin et maxd’un signedcharUCHAR MIN, UCHAR MAX valeursmin et maxd’un unsignedchar

INT MIN, INT MAX valeursmin et maxd’un intUINT MIN, UINT MAX valeursmin et maxd’un unsignedintSHRT MIN, SHRT MAX valeursmin et maxd’un short

USHRT MIN, USHRT MAX valeursmin et maxd’un unsignedshortLONG MIN, LONG MAX valeursmin et maxd’un long

ULONG MIN, ULONG MAX valeursmin et maxd’un unsignedlong

� float.h �FLT DIG nombredechiffressignificatifspourun float

FLT EPSILON pluspetit float f tel que IJ�K� � 45L%M� � 4FLT MIN pluspetit nombrerepresentableFLT MAX plusgrandnombrerepresentable

Lesmemesconstantesexistentpourlesdouble, enecrivantDBL aulieu deFLT .

8.8 � stdarg.h � : fonctionsa nombre variable d’ar guments

Les declarationsde � stdarg.h� permettentde construiredesfonctionsayantuneliste d’argumentsde longueurinconnueet ayantdestypesinconnusa la compilation.

La declarationd’une telle fonction sefait commeunefonction normale,mis a part quel’on ecrit despointsdesuspensionapres le dernierargument.La fonction doit avoir au moins un argumentnomme. On declareensuiteal’int erieurdela fonctionunevariabledetypeva list, et on l’initialise enappelantvoid va start(va list vl, last) aveccommeargumentsla va list et le dernierargumentnommedela fonction.

Pouraccederensuitea chaqueelementde la liste d’arguments,on appellela macrova arg(va list vl, type) quiretournela valeurdu parametre.typeestle nomdu typede l’objet a lire. Enfin il ne fautpasoublierd’appelervoidva end(va list vl) a la fin dela fonction.

Commepetit exemple,voici unefonction qui ajoutetoussesarguments,chaqueargumentetantprecede de sontype int ou double:

#include <stdio.h>#include <stdarg.h>

/* un type enumere decrivant les types ! */typedef enum {INT, DOUBLE} montype;

6 fevrier2000 Aide-memoire deLangage C DamienMercier 39

/* chaque element est ecrit *//* sous la forme "type" puis "valeur" *//* le premier argument est le nombre d’elements */double somme (int nb, ...) {

va_list vl;float f=0.0;int i;int vali;float valf;

va_start(vl, nb);for (i=0;i<nb;i++) {

switch (va_arg(vl,montype)) {case INT:

vali=va_arg(vl,int);printf("Ajout de l’entier %d\n",vali);f += (float)vali;break;

case DOUBLE:valf=va_arg(vl,double);printf("Ajout du flottant %f\n",valf);f += valf;break;

default:printf("Type inconnu\n");

}}va_end(vl);return f;

}

main() {int a,b,c,d;double e,f,g;double result;

a=2; b=3; c=-5; d=10;e=0.1; f=-32.1; g=3.14e-2;result=somme(7, INT,a,DOUBLE,e,DOUBLE,f,INT,b,INT ,c,INT ,d,DO UBLE,g);printf("Somme: %f\n",result);exit(0);

}

Qui affichea l’execution:Ajout de l’entier 2Ajout du flottant 0.100000Ajout du flottant -32.099998Ajout de l’entier 3Ajout de l’entier -5Ajout de l’entier 10Ajout du flottant 0.031400Somme: -21.968597

Un dernierexempleclassique,unefonctionsimilairea printf() :

#include <stdio.h>#include <stdarg.h>

40 DamienMercier Aide-memoire deLangage C 6 fevrier2000

/* mini fonction printf *//* elle utilise printf ... mais *//* l’idee est tout de meme la */int monprintf(char *format, ...) {

va_list vl;int nb=0;

va_start(vl, format);

do {if (*format != ’%’) {

nb++;putchar(*format);continue;

};format++;switch (*format) {

case ’d’:nb+=printf("%d",(int)va_arg(vl,int)) ;break;

case ’s’:nb+=printf("%s",(char *)va_arg(vl,char *));break;

case ’f’:nb+=printf("%f",(double)va_arg(vl,do uble) );break;

default:fprintf(stderr,"Probleme de format");

}} while (*(++format) !=’\0’);

va_end(vl);return nb;

}

main() {int a;int t;char s[30];double b,c;

a=1;b=2.0;c=a+b;sprintf(s,"CQFD");monprintf("Voila : %d + %f = %f ; %s\n",a,b,c,s);exit(0);

}

L’executionduprogrammedonnealors:Voila : 1 + 2.000000 = 3.000000 ; CQFD