Tekstitiedostot ja niiden käyttö

Samankaltaiset tiedostot
ehdollinen kääntäminen

Tekstitiedostot ja niiden käyttö

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

ehdollinen kääntäminen

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

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

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

Binäärioperaatiot Tiedostot ja I/O

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

Loppukurssin järjestelyt

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

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

// // 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

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

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

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

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

Lyhyt kertaus osoittimista

13. Loogiset operaatiot 13.1

Ohjausrakenteet. Valinta:

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

Ohjelmoinnin perusteet Y Python

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

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Java-kielen perusteet

TIETORAKENTEET JA ALGORITMIT

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ä.

Java-kielen perusteita

Tietorakenteet ja algoritmit

12. Javan toistorakenteet 12.1

5. HelloWorld-ohjelma 5.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

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

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

16. Ohjelmoinnin tekniikkaa 16.1

Ohjelmoinnin perusteet Y Python

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

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

Tietotyypit ja operaattorit

11. Javan toistorakenteet 11.1

12. Javan toistorakenteet 12.1

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

Muuttujien roolit Kiintoarvo cin >> r;

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

11. Javan valintarakenteet 11.1

13. Loogiset operaatiot 13.1

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

Ohjelmoinnin perusteet Y Python

C-ohjelmointi, kevät Merkkijonot Komentoriviparametrit. Luento

Merkkijonot Komentoriviparametrit

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

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

Java-kielen perusteet

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

Merkkijonot Komentoriviparametrit

7. Näytölle tulostaminen 7.1

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

Ohjelmoinnin perusteet Y Python

Kieliteknologian ATK-ympäristö Kuudes luento

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

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

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

12. Näppäimistöltä lukeminen 12.1

Osoittimet ja taulukot

Harjoitus 4 (viikko 47)

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

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

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

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

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin perusteet Y Python

Transkriptio:

, syksy 2007 qtekstitiedostot ja niiden käyttö qesikääntäjä, makrot ja ehdollinen kääntäminen Luento 3 12.9.2007 Syksy 2007 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 2007 2 1

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ä! Syksy 2007 3 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 2007 4 2

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 2007 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 2007 6 3

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 2007 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 2007 8 4

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 2007 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 2007 10 5

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 2007 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 2007 12 6

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 2007 13 if(fscanf(f, "%lf%lf%lf", &x, &y, &z)!= 3) { fprintf(stderr, Tiedoston lukeminen \ epäonnistui\n"); return EXIT_FAILURE; Tiedoston lukemisfraasi Idiom? printf("%f\n", x + y + z); if(fclose(f) == EOF) { fprintf(stderr, "Sulkeminen epäonnistui\n"); return EXIT_FAILURE; return EXIT_SUCCESS; Tiedoston sulkemisfraasi 7

Rivin loppu ja tiedoston loppu /* Lukee tiedostosta yhden rivin ja tulostaa sen näytölle */ while((c = fgetc(tkahva))!='\n') if (c == EOF) break; 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 2007 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 2007 16 8

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. Syksy 2007 17 Tiedoston avaaminen: if ((filehandle = fopen(fname, fmode)) ==NULL) /* failed */ if (close(filehandle) == EOF). /* failed */ if ((c = fgetc(filehandle)) == EOF) /* error */ Tiedoston sulkeminen 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 9

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 2007 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 2007 20 10

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 2007 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 2007 22 11

Makronimen korvaus makroarvolla Esikääntäjä korvaa lähdetiedostossa jokaisen makronimi esiintymän makroarvon tekstillä. #define PI 3.14 i=pi; korvaus => i=3.14 #define PII =3.14; i=pii; korvaus => i ==3.14;; VÄÄRIN!!!! Syksy 2007 23 Esimerkkejä makron käytöstä #define PROMPT printf("enter real value: ") #define SKIP while(getchar()!= '\n'); 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 2007 24 12

Parametrilliset makrot #define makronimi(parametrit) makroarvo esim. #define READ(c, tkahva) (c=fgetc(tkahva)). if (READ(char, tied1) == x ) => if ( (char = fgetc(tied1))== x ) <eri asia kuin> if ( char = fgetc(tied1)== x ) =>>> Siis käytä runsaasti sulkuja! Syksy 2007 25 Varovaisuutta, huolellisuutta makrojen käytössä! Makroja käytettäessä syntyy helposti sivuvaikutuksia Makro voi helpottaa kirjoittamista, mutta koodin luettavuus voi kärsiä! #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 2007 26 13

#-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 2007 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 2007 28 14

Ennaltamääritellyt makrot 4 kappaletta LINE lähdekoodin tämän rivin numero FILE tämän lähdekoodin nimi TIME käännösaika STDC 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 ); Syksy 2007 29 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 2007 30 15

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*/ kootaan yleensä otsaketiedostoiksi.h Syksy 2007 31 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) Syksy 2007 32 16

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 #else part2 #ifndef macroname partl #else part2 #if constantexpression1 part 1 #elif constantexpression2 part2 #else part3 Syksy 2007 33 #if constantexpression1 part1 #elif constantexpression2 part2 #else part3 - voi olla useita #elif osia - #else voi puuttua #if defined (name) /*onko name määritelty?*/ #error textmessage #if defined ( STDC ). #else #error Jotain pielessä 17

Käyttö virheenjäljityksessä 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! # if 0 poisjätettävä osa Näin sama lähdekoodi voi toimia sekä testiversiona että tuotantoversiona! Syksy 2007 35 Testikoodin poisjättäminen #define DEB /* vain määritelty */ #ifdef DEB /*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 2007 36 18

Esimerkkejä: Example int main() { int i, j; printf("enter two integer values: "); if(scanf("%d%d", &i, &j)!= 2) return EXIT_FAILURE; #ifdef DEB printf("entered %d and %d\n", i, j); printf("sum = %d\n", i + j); return EXIT_SUCCESS; Mitä hyötyä! int i, j; #ifdef DEB int res; if( #ifdef DEB (res = scanf(%d%d, &i, &j) #ifdef DEB ) )!= 2 ) Example #ifdef DEB { switch(res) { case 0: printf("both values were wrong\n"); break; case 1: printf("ok first value %d\n", i); break; case EOF: printf("eof\n"); break; case 2: printf("both OK\n"); break... Enemmän informaatiota! 19

int main() { const char SENTINEL =. ; int aux, maxi=0; #ifdef DEBUG printf( Virheenjäljitys päällä: kopioidaan kaikki merkit\n ); while(1) { if ((aux = getchar()) == EOF aux == SENTINEL) break; #ifdef DEBUG putchar(aux); putchar( \n ); if (aux > maxi) { #ifdef DEBUG printf( Suurin merkki on nyt: %c\n, aux); maxi = aux; #ifdef DEBUG putchar( \n ); printf( Suurin merkki on: %d\n, maxi); return EXIT_SUCCESS; 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 2007 40 20

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ä makro NDEBUG joko makromäärittelyssä #define NDEBUG tai kääntäjän parametrina gcc DNDEBUG. Syksy 2007 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 2007 42 21

#include<assert.h> void open_record(char *record_name) { assert(record_name!=null); /* Rest of code */ int main(void) { open_record(null); Syksy 2007 43 Makro otsaketiedostojen suojana 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 2007 44 22

Ehdollinen kääntäminen ja siirrettävyys Erilaisissa ympäristöissä toimivien ohjelmien kehittämiseen: #if IBMPC /* ehtolauseke */ #include <ibm.h> #else #include <generic.h> #ifdef IBMPC /*makromäärittely*/ typedef int MyInteger #else typedef long MyInteger Syksy 2007 45 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 j = HIGH; FOR(j) switch(j) { case 1: PR(i++); case 2: PR(j); break; default: PR(i); printf ( \n%s\n, SHOW(3)); return EXIT_SUCCESS; 23

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)); break; default: PR(i); printf( %d\n, (i)); printf ( \n%s\n, SHOW(3)); return EXIT_SUCCESS; 24