Tiedostokahva (filehandle) Tekstitiedostot. Tiedoston avaaminen. Tiedoston käyttötavat. Tekstitiedostot ja niiden käyttö. C-ohjelmointi, syksy 2008

Samankaltaiset tiedostot
Tekstitiedostot ja niiden käyttö

Tiedostokahva (filehandle) Tekstitiedostot. Tiedoston avaaminen. Tiedoston käyttötavat. Tekstitiedostot ja niiden käyttö. C-ohjelmointi, kevät 2006

ehdollinen kääntäminen

Tekstitiedostot ja niiden käyttö

ehdollinen kääntäminen

Tiedostot. Tiedostot. Tiedostot. Tiedostot. Tiedostot. Tiedostot

Moduli 5: Kehittyneitä piirteitä

Luennon sisältö Tyypit int, char, float, double signed, unsigned short, long Vakiot const Rakenteet if, for, while, switch, do-while Syöttö ja tulostu

Binäärioperaatiot Tiedostot ja I/O

Binäärioperaatiot Tiedostot ja I/O

Loppukurssin järjestelyt

C-kurssi kevät Luennon sisältö

Luennon sisältö. C-kurssi kevät Tasokokeen kohta 1: Taulukon järjestäminen. Tasokokeen kohta 2. Tasokokeen kohta 2. Tasokokeen kohta 3

Tiedosto on yhteenkuuluvien tietojen joukko, joka tavallisimmin sijaitsee kiintolevyllä, muistitikulla tai jollakin muulla fyysisellä tietovälineellä.

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

C-kurssi syksy ltö. Luennon sisält. Luento 2: tyypit, rakenteet, makrot Tyypit. signed, unsigned short,, long Vakiot const Rakenteet

Luennon sisält. ltö. C-kurssi syksy ääreet: int ja char. Yksinkertaiset tyypit. Kokonaisluvut. Merkit

// // whiledemov1.c // #include <stdio.h> int main(void){ int luku1 = -1; int luku2 = -1;

Loppukurssin järjestelyt C:n edistyneet piirteet

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

C-ohjelmointi, syksy 2006

C-ohjelmointi, syksy Yksiulotteiset taulukot Moniulotteiset taulukot Dynaamiset taulukot. Binääritiedostot. Luento

Luennon sisältö. Taulukot (arrays) (Müldnerin kirjan luku 10) Yksiulotteiset taulukot. Mikä taulukko on? Taulukko-osoitin. tavallinen osoitin

C-kurssi kevät t Luento 2: tyypit, rakenteet, makrot

Lyhyt kertaus osoittimista

13. Loogiset operaatiot 13.1

Ohjausrakenteet. Valinta:

Ohjelmoinnin perusteet Y Python

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Tietueet. Tietueiden määrittely

Luento 5. Timo Savola. 28. huhtikuuta 2006

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Java-kielen perusteet

TIETORAKENTEET JA ALGORITMIT

Rakenne. C-ohjelmointi: Tietorakenteita ja tyyppejä. Tyyppimuunnoksia aritmeettisten tyyppien välillä. Tyyppimuunnokset. & (bitti and) Bittioperaatiot

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Ohjelmointiharjoituksia Arduino-ympäristössä

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

Modulaarisessa ohjelmoinnissa jaetaan ohjelma osiin (moduuleihin), jotka ovat yksinkertaisia ja lyhyitä.

Tietorakenteet ja algoritmit

Java-kielen perusteita

5. HelloWorld-ohjelma 5.1

12. Javan toistorakenteet 12.1

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Esimerkki 1: Kahviautomaatti.

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

16. Ohjelmoinnin tekniikkaa 16.1

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

C-kieli mahdollistaa hyvin tiiviin ja samalla sekavan tavan esittää asioita, kuitenkin hyvän ohjelman tulisi olla mahdollisimman helppolukuinen ja

16. Ohjelmoinnin tekniikkaa 16.1

Ohjelmoinnin perusteet Y Python

Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin

21. oppitunti. Esikäsittelijä. Osa. Esikäsittelijä ja kääntäjä

Tietotyypit ja operaattorit

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 5: Python

12. Javan toistorakenteet 12.1

11. Javan toistorakenteet 11.1

#include <stdio.h> // io-toiminnot. //#define KM_MAILISSA int main( ){

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

11. Javan valintarakenteet 11.1

Ohjelmoinnin perusteet Y Python

13. Loogiset operaatiot 13.1

5. HelloWorld-ohjelma 5.1

tietueet eri tyyppisiä tietoja saman muuttujan arvoiksi

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

2. C-kieli ja ongelmanratkaisu

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

7. Näytölle tulostaminen 7.1

Java-kielen perusteet

Ohjeet. AS C-ohjelmoinnin peruskurssi Aalto-yliopiston sahkotekniikan korkeakoulu Tentti , Raimo Nikkila

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Ohjelmoinnin perusteet Y Python

Kieliteknologian ATK-ympäristö Kuudes luento

C-ohjelmointi, syksy Merkkijonot Komentoriviparametrit. Luento C-ohjelmointi Syksy

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

Osoittimet ja taulukot

C-ohjelmointi, kevät Merkkijonot Komentoriviparametrit. Luento

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Merkkijonot Komentoriviparametrit

Harjoitus 4 (viikko 47)

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 6: Python

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

Ohjelmoinnin perusteet Y Python

ATK tähtitieteessä. Osa 4 - IDL input/output. 19. syyskuuta 2014

Sisällys. 12. Javan toistorakenteet. Yleistä. Laskurimuuttujat

Ehto- ja toistolauseet

ITKP102 Ohjelmointi 1 (6 op)

Automaattiteoria diskreetin signaalinkäsittelyn perusmallit ja -menetelmät ( diskreettien I/O-kuvausten yleinen teoria)

Merkkijonot Komentoriviparametrit

Transkriptio:

, syksy 2008 qtekstitiedostot ja niiden käyttö qesikääntäjä, makrot ja ehdollinen kääntäminen Luento 3 9.9.2008 Syksy 2008 1 Tekstitiedostot ja niiden käyttö Tekstitiedosto Tiedostokahva (Müldnerin kirjassa luku 5) binääritiedosto Tiedoston avaaminen ja sulkeminen Tiedoston käyttötavat Virhetilanteet avauksessa ja sulkemisessa Standarditiedostot Perus I/O-operaatiot tiedostoille Lukeminen ja kirjoittaminen Esimerkkejä ja idiomeja Syksy 2008 2 Tekstitiedostot Tiedostot ovat pelkkiä tavujonoja. Tiedoston päättää tiedoston lopetusmerkki EOF. Kahdenlaisia tiedostoja; ero niiden käsittelyssä Tekstitiedostot käsitellään riveittäin. Joka rivin lopussa on rivin loppumismerkki ( uuden rivin alkamismerkki ) \n. Binääritiedostossa ei ole mitään erityistavuja. Eri käyttöjärjestelmät käyttävät eri tapoja ilmaisemaan rivin tai tiedoston päättymistä! Tiedostokahva (filehandle) Tiedostokahva on tiedostoon osoittava osoitin (pointer), jonka avulla tiedostoa käsitellään. Tiedostokahvan määrittely: FILE*kahva; FILE *tied1, *tied2; typedef FILE* P_FILE; /*määritellään ensin P_FILE tied1, tied2; tiedostokahvatyyppi */ Syksy 2008 3 Syksy 2008 4 Tiedoston avaaminen Ennen käyttöä tiedosto on avattava käyttäen funktiota fopen(). Avaus yhdistää tiedoston tiedostokahvaan. Avattaessa ilmoitetaan tiedoston nimi sekä tiedoston käyttötapa. kahva = fopen( testitiedosto, r ); tied1 = fopen( MyFile.txt, w ); tied2 = fopen( test.out, wb ); Syksy 2008 5 Tiedoston käyttötavat "r" lukeminen jo olemassa olevasta tiedostosta "w" kirjoittaminen: olemassa olevan tiedoston päälle (overwrite) tai uuteen tiedostoon, joka luodaan vasta tässä (create) "a" kirjoittaminen joko olemassa olevan tiedoston perään (append) tai uuteen luotavaan tiedostoon "r+" lukeminen ja kirjoittaminen, muuten kuten "r" "w+" lukeminen ja kirjoittaminen, muuten kuten "w" "a+" lukeminen ja kirjoittaminen, muuten kuten "a" Jos halutaan käsitelllä tiedostoa binäärimuotoisesti, niin lisätään ylläoleviin merkki b: "r+b. Jos tiedosto on avattu sekä lukemista että kirjoittamista varten, I/O-operaatioiden välillä on aina kutsuttava jotain funktioista: fseek(), fsetpos(), rewind() tai fflush(). Syksy 2008 6 1

Tiedoston avaaminen voi epäonnistua! Jos tiedoston avaaminen ei onnistu, niin fopen palauttaa arvon NULL (= erityinen nolla-arvo), muuten osoittimen tiedostoon eli tiedostokahvan. Joka kerta tiedostoa avattaessa on siis varmistuttava, että avaus onnistui! if (filehandle = fopen(fname, fmode)) == NULL) /* toiminta virhetilanteessa */ Syksy 2008 7 Tiedostonimet, avattujen tiedostojen maksimimäärä Tiedostonimi voi myös olla polkunimi. Eri käyttöjärjestelmissä on erilaisia polkunimiä. Näissä voi olla merkkejä, joilla on erityismerkitys C-kielessä. (Esim. DOS-järjestelmän \-merkki) \ on escape-merkki, joka muuttaa seuraavan merkin merkityksen => DOS:n \-merkki korvattava \\-merkeillä FILENAME_MAX (stdio.h) kertoo tiedostonimen maksimipituuden. Avattujen tiedostojen määrä järjestelmässä on rajoitettu: enintään FOPEN_MAX (stdio.h) tiedostoa. Syksy 2008 8 Tiedoston sulkeminen Avattu tiedosto täytyy sulkea, kun sitä ei enää tarvita. Tiedosto suljetaan käyttäen funktiota fclose(). Parametrina annetaan suljettavan tiedoston kahva. Jos sulkeminen epäonnistuu, niin fclose palauttaa EOF-merkin. Aina varmistettava onnistuminen! if (fclose(tied1) == EOF) /* toiminta, kun tiedostoa ei saada suljettua */ Syksy 2008 9 Standarditiedostot: stdin, stdout ja stderr Aina käytettävissä olevat ennaltamääritellyt, tiedostoonsa kiinnikolvatut tiedostokahvat Ei tarvitse erikseen avata eikä sulkea! stdin standardisyöttövirta; yleensä näppäimistö stdout standarditulostusvirta; yleensä näytölle stderr standardivirhetulostusvirta; eri kuin normaalitulostus FILE *inkahva;. inkahva = stdin; /* inkahva on synonyymi stdin-kahvalle */ Syksy 2008 10 I/O-operaatiot tiedostoille (perusoperaatiot) Perusoperaatiot ovat hyvin samankaltaisia kuin pääte-i/o:ssa tai formatoidussa I/O:ssa käytetyt: int fgetc (filehandle) int fputc (int, filehandle) int fscanf (filehandle,..) ~ int getchar() ~ int putchar(int) ~ int scanf( ) int fprintf (filehandle, ) ~ int printf( ) Syksy 2008 11 Merkin ja luvun lukeminen tiedostosta Yhden merkin lukeminen tiedostosta if ((c=fgetc(filehandle)) == EOF) /* toiminta tiedoston loppuessa */ Yhden luvun lukeminen tiedostosta if (fscanf (filehandle, %d, &i)!= 1) /* toiminta lukemisen epäonnistuessa */ Syksy 2008 12 2

Esimerkki: Ohjelma lukee kolme lukua tiedostosta luvut ja tulostaa niiden summan näytölle. int main() { FILE *f; double x, y, z; Tiedoston avaamisfraasi! if((f = fopen( luvut", "r")) == NULL) { fprintf(stderr, Ei avaudu: %s\n", luvut"); return EXIT_FAILURE; Syksy 2008 13 if(fscanf(f, "%lf%lf%lf", &x, &y, &z)!= 3) { fprintf(stderr, Tiedoston lukeminen \ epäonnistui\n"); return EXIT_FAILURE; Tiedoston Idiom? lukemisfraasi printf("%f\n", x + y + z); if(fclose(f) == EOF) { fprintf(stderr, "Sulkeminen epäonnistui\n"); return EXIT_FAILURE; Tiedoston sulkemisfraasi Rivin loppu ja tiedoston loppu /* Lukee tiedostosta yhden rivin ja tulostaa sen näytölle */ while((c = fgetc(tkahva))!='\n') if (c == EOF) else putchar(c); if(c!= EOF) putchar(c); /* Etsitään vain rivin loppu */ while((c = fgetc(tkahva))!='\n ); /* Lasketaan rivin merkkien määrä */ while((c = fgetc(tkahva))!='\n ) ccount++; Syksy 2008 15 Laadi ohjelma, joka laskee ja tulostaa tiedoston testi.txt rivien lukumäärän. q Määrittelyt q Avaa tiedosto testi.txt q tiedoston rivien lukumäärän laskeminen q Niin kauan kuin tiedostoa riittää (eli ei vielä EOF-merkki) q Jos \n merkki, niin kasvata rivien lukumäärää. q Tulosta lukumäärä näytölle q Sulje tiedosto testi.txt Syksy 2008 16 ungetc, feof ungetc (char, filehandle); Palauttaa luetun merkin tiedostoon eli laittaa sen takaisin tiedoston lukupuskuriin, josta se luettavissa uudestaan. Itse tiedostoa ei muuteta. while (ehto (c = fgetc (tiedostokahva))) prosessoi c; ungetc (c, tiedostokahva); feof(filehandle); Testaa tiedoston loppumista. Palauttaa 0, jos tiedosto on loppu, muuten jonkun muun arvon. Tiedoston avaaminen: if ((filehandle = fopen(fname, fmode)) ==NULL) /* failed */ if (close(filehandle) == EOF). /* failed */ Tiedoston sulkeminen if ((c = fgetc(filehandle)) == EOF) /* error */ Yhden merkin lukeminen if (fscanf (filehandle, %d, &i)!=1) /* error */ Yhden luvun lukeminen while ((c= fgetc(filehandle))!= \n ) while ((c= fgetc(filehandle))!= EOF) Rivin loppuun lukeminen Tiedoston loppuun lukeminen Fraaseja tiedoston käsittelyyn Syksy 2008 17 3

Esikääntäjä, makrot ja ehdollinen kääntäminen (Mülderin kirjan luku 6) C-esikääntäjä Makrot Parametrittomat makrot Parametrilliset makrot Ennaltamääritellyt makrot Ulkoisten tiedostojen sisällyttämimen Ehdollinen kääntäminen Eri tavat toteuttaa Käyttö virheenjäljityksessä Assert-makro ja sen käyttö Käyttö otsaketiedostoissa Käyttö siirrettävyyden lisäämiseksi Syksy 2008 19 C-esikääntäjä #-merkillä alkavat komentorivit tarkoitettu esikääntäjälle => oma syntaksi käsitellään ennen kääntämistä Mihin käytetään? Makrot: korvataan teksti toisella tekstillä Ulkoisten tiedostojen liittäminen #include <stdio.h> Ehdollinen kääntäminen: vain osa lähdetiedostoa käännetään tietyn ehdon ollessa voimassa; hyötyä virheiden etsinnässä Syksy 2008 20 Makrotyypit Parametrittomat makrot Lyhennemerkintä; makronimi korvataan aina samalla tekstillä Parametrilliset makrot Parametrit vaikuttavat korvaustekstiin => monipuolisempi, mutta helposti myös yllättäviä sivuvaikutuksia Ennaltamääritellyt makrot C-toteutuksessa jo sisällä Hyötyä virhetilanteessa Syksy 2008 21 Parametriton makro #define makronimi makroarvo #define PI 3.14 #define PII 3.14159265358979323\ 846264338327950 #define SCREEN_W 80 #define SCREEN_H 25 MakroNimi ISOILLA KIRJAIMILLA! MakroArvo rivin loppuun ( \n -merkkiin asti) \ = jatkuu seuraavalle riville Huomaa: ei =-merkkiä eikä puolipistettä(;)! Syksy 2008 22 Makronimen korvaus makroarvolla Esikääntäjä korvaa lähdetiedostossa jokaisen makronimi esiintymän makroarvon tekstillä. Esimerkkejä makron käytöstä #define PROMPT printf("enter real value: ") #define SKIP while(getchar()!= '\n'); #define PI 3.14 i=pi; korvaus => i=3.14; #define PII =3.14; i=pii; korvaus => i ==3.14;; VÄÄRIN!!!! Käytä runsaasti sulkuja, etenkin aritmeettisissa lausekkeissa! #define A 2 + 4 Haluttiinko todella tätä? #define B A * 3 => B = 2 + 4 * 3 = 14 #define A (2 + 4) #define B (A * 3) => B = ((2+4) * 3) =18 Syksy 2008 23 Syksy 2008 24 4

Parametrilliset makrot #define makronimi(parametrit) makroarvo esim. #define READ(c, tkahva) (c=fgetc(tkahva)). if (READ(ch, tied1) == x ) => if ( (ch = fgetc(tied1))== x ) Varovaisuutta, huolellisuutta makrojen käytössä! Makroja käytettäessä syntyy helposti sivuvaikutuksia Makro voi helpottaa kirjoittamista, mutta koodin luettavuus voi kärsiä! <eri asia kuin> if ( ch = fgetc(tied1)== x ) =>>> Siis käytä runsaasti sulkuja! #define SQR(x) (x*x) SQR(z+1); => (z+1*z+1) #define SQR(x) ((x)*(x)) SQR(z+1); => ((z+1)*(z+1)) Syksy 2008 25 Syksy 2008 26 #-merkin muu käyttö Kommenteissa ja merkkijonovakioissa olevia makronimiä ja parametreja ei hyväksytä! määrittelyssä parametrin eteen pitää laittaa #-merkki, jolloin sen arvo makron laajennuksessa laitetaan lainausmerkkien sisään #parametri => parametri Merkkien yhteenliittäminen #define TEMP(i) temp ##i TEMP(1) = TEMP(2) => temp1 = temp2 Syksy 2008 27 #define EMPTY (maxused == 0) #define ASSERT if (!(EMPTY? current == 0 : \ 0 < current && current <=maxused)) {\ fprintf(stderr, invariant failed; current = %d \t; \ maxused= %d\n, current, maxused); \ exit(1); EMPTY? current == 0 : 0 < current && current <=maxused ehdollinen lauseke Syksy 2008 28 Ennaltamääritellyt makrot 4 kappaletta LINE FILE TIME STDC lähdekoodin tämän rivin numero tämän lähdekoodin nimi käännösaika 1, jos kääntäjä noudattaa ANSI C:tä if (n>10) { /* virhetilanne */ fprintf (stderr, liian suuri n:n arvo tiedoston %s return EXIT_FAILURE; rivillä %d! \n", FILE, LINE ); Makromäärittelyn purkaminen #undef PI jos halutaan määritellä uudestaan PI, niin entinen määrittely on purettava Muuten voi tulla ongelmia! Makromäärittelyn voi purkaa myös kääntäjän komentorivillä Syksy 2008 29 Syksy 2008 30 5

Ulkoisen tiedoston lisääminen lähdekoodiin kaksi eri muotoa: miten lisättävä tiedostoa haetaan hakemistosta #include filename /* käyttäjän oma tiedosto, haetaan ensin nykyhakemistosta*/ #include <filename> /*järjestelmän tiedosto, haetaan ensin systeemihakemistosta*/ Standard Header Files stdio.h - the basic declarations needed to perform I/O ctype.h - for testing the state of characters math.h - mathematical functions, such as abs() and sin() (linking lm) kootaan yleensä otsaketiedostoiksi.h Syksy 2008 31 Syksy 2008 32 Ehdollinen kääntäminen (Conditional Compilation) = tietyssä tilanteessa, tietyn ehdon ollessa tosi osa koodia jätetään kääntämättä Käytetään virheenjäljityksessä, otsaketiedostoissa siirrettävää koodia tuotettaessa Kaksi eri tapaa #ifdef macroname part1 part2 #ifndef macroname partl part2 #if constantexpression1 part 1 #elif constantexpression2 part2 part3 Syksy 2008 33 #if constantexpression1 part1 #elif constantexpression2 part2 part3 #if defined ( STDC ). #error Jotain pielessä - voi olla useita #elif osia - voi puuttua #if defined (name) /*onko name määritelty?*/ #error textmessage Käyttö virheenjäljityksessä Testikoodin poisjättäminen Ehdollinen kääntäminen on poiskommentointia parempi tapa poistaa kulloinkin turhat koodin osat. esim. virheenjäljitystä varten lisätyt tulostuskomennot C:ssä ei saa olla sisäkkäisiä kommentteja! # if0 poisjätettävä osa Näin sama lähdekoodi voi toimia sekä testiversiona että tuotantoversiona! Syksy 2008 35 #define DEB /* vain määritelty */ /*jokin virheenjäljitys lause esim. tulostuslause */ printf("value of i = %d", i); /* tuotantokoodia */ Kääntäjän komentorivillä! gcc UDEB prog.c makromäärittely poispäältä gcc DDEB prog.c makromäärittely päälle Syksy 2008 36 6

Esimerkkejä: Example int main() { int i, j; printf("enter two integer values: "); if(scanf("%d%d", &i, &j)!= 2) return EXIT_FAILURE; printf("entered %d and %d\n", i, j); printf("sum = %d\n", i + j); Mitä hyötyä! int i, j; int res; if( (res = scanf(%d%d, &i, &j) ) )!= 2 ) Enemmän informaatiota! Example { switch(res) { case 0: printf("both values were wrong\n"); case 1: printf("ok first value %d\n", i); case EOF: printf("eof\n"); case 2: printf("both OK\n"); break... int main() { const char SENTINEL =. ; int aux, maxi=0; UG printf( Virheenjäljitys päällä: kopioidaan kaikki merkit\n ); while(1) { if ((aux = getchar()) == EOF aux == SENTINEL) UG putchar(aux); putchar( \n ); if (aux > maxi) { UG printf( Suurin merkki on nyt: %c\n, aux); maxi = aux; UG putchar( \n ); printf( Suurin merkki on: %d\n, maxi); Assert makro virheenjäljityksessä (1) assert (int lauseke) (assert.h) Diagnostiikkatietojen kirjoittaminen standardivirhetiedostoon (stderr) Jos lauseke on epätosi (false, 0), niin virhetiedostoon kirjoitetaan lauseke, lähdekooditiedoston nimi ja rivin numero: Assertion failed: ehto, file tiednimi, line rivinro (Tiedostonimi ja rivinumero saadaan makroista FILE ja LINE.) ja ohjelman suoritus keskeytetään abort()-funktiolla. assert-makroilla varmistetaan, että ohjelma toimii kuten sen loogisesti oletetaan toimivan: ennakkoehtoja, jälkiehtoja, oletuksia muuttujien arvoista. Esimerkkejä lausekkeista: assert (i>=0) assert (b*b 4*a*c >=0) assert (0<=i && i <size) Syksy 2008 40 Assert makro virheenjäljityksessä (2) Assert-makron toimintaa säätelee makron NDEBUG ( = no debug) määrittely. Jos NDEBUG on määritelty, niin assert ei tee mitään. Oletusarvoisesti assert() on käytössä ja valvoo ohjelman toimintaa. Tarkistukset poistetaan ohjelmasta määrittelemällä makrondebug joko makromäärittelyssä #define NDEBUG tai kääntäjän parametrina gcc DNDEBUG. Syksy 2008 41 Esimerkki assert-koodista /* Assert.cc for GNU C/C++ */ /* #ifdef ASSERT # ifndef NDEBUG */ #ifdef ASSERT void AssertionFailure(char *exp, char *file, char *basefile, int line) { if (!strcmp(file, basefile)) { fprintf(stderr, "Assert(%s) failed in file %s, line %d\n", exp, file, line); else{ fprintf(stderr, "Assert(%s) failed in file %s (included from %s), line %d\n", exp, file, basefile, line); Syksy 2008 42 7

Makro otsaketiedostojen suojana #include<assert.h> void open_record(char *record_name) { assert(record_name!=null); /* Rest of code */ int main(void) { open_record(null); Syksy 2008 43 Ehdollisella kääntämisellä varmistetaan, että otsaketiedosto käännetään vain kerran: kukin otsaketiedosto ympäröidään makrolla, joka suoritetaan vain kerran. Useasta osasta koottavaan ohjelmaan tulee helposti sama otsaketiedosto useaan kertaan => käännösvirhe Makro nimetään otsaketiedoston mukaan: screen.h => käytetään makronimeä SCREEN_H #ifndef SCREEN_H #define SCREEN_H /*otsaketiedoston sisältö */ #include screen.h #include screen.h Käännetään vain kerran! Syksy 2008 44 Mitä seuraava ohjelma tulostaa? Ehdollinen kääntäminen ja siirrettävyys Erilaisissa ympäristöissä toimivien ohjelmien kehittämiseen: #if IBMPC /* ehtolauseke */ #include <ibm.h> #include <generic.h> #ifdef IBMPC /*makromäärittely*/ typedef int MyInteger typedef long MyInteger Syksy 2008 45 #define LOW -2 #define HIGH (LOW+5) #define PR(arg) printf( %d\n, (arg)) #define FOR(arg) for(; (arg); (arg)--) #define SHOW(x) x int main(){ int i = LOW; int j = HIGH; FOR(j) switch(j) { case 1: PR(i++); case 2: PR(j); default: PR(i); printf ( \n%s\n, SHOW(3)); Mitä seuraava ohjelma tulostaa? #define LOW -2 #define HIGH (LOW+5) #define PR(arg) printf( %d\n, (arg)) #define FOR(arg) for(; (arg); (arg)--) #define SHOW(x) x int main(){ int i = LOW; int i = -2; int j = HIGH; int j = (-2 + 5); /* = 3*/ FOR(j) for (; (j); (j)--) switch(j) { case 1: PR(i++); printf( %d\n, (i++)); case 2: PR(j); printf( %d\n, (j)); default: PR(i); printf( %d\n, (i)); printf ( \n%s\n, SHOW(3)); 8