Göm menyn

TDIU08 Problemlösning och programmering

Enkel felsökning av program


Man bör förstå skillnaden mellan vad som är fel av olika sorter. Vi tar upp följande två varianter i denna kurs. Fel vid kompilering och fel vid exekvering.

Kompileringsfel

Att få kompileringsfel är något som alla får. Dessa är dessutom de fel som är allra lättast att hitta och åtgärda. Man skall vara tacksam att kompilatorn ger bra felmeddelanden. Speciellt är gnatmake som är gjord för Ada är otroligt bra gjord (och snäll) tack vare att Ada är så väl specificerat jämfört med många andra programmeringsspråk. Det är en av anledningarna till att vi vill börja med Ada som första programmeringsspråk.

När man får ett kompileringsfel står det ofta vilken rad i koden som felet "upptäcktes" på. OBS! Detta är den rad där kompilatorn gissar att felet är. Det riktiga felet kan dock ligga tidigar då det kan vara så att kompilatorn kan ha olika alternativ att klara av kompileringen. Kolla därför även lite ovanför den rad som anges om du inte hittar felet.

I Ada är dock kompilatorn väldigt duktig på att hitta vilken rad felet är så det är nästan alltid rätt rad som anges.

I boken finns (i slutet) ett kapitel om Gnat-kompilatorn där det finns några vanliga fel uppräknade. Lägg gärna till fler sådana så att du har koll på vad de betyder när du kommer till tentan.

Exekveringsfel (fel vid programkörning)

Lite mer beskrivning om denna svårare felsökning. När ditt program går att kompilera och köra, men inte fungerar som det skall. Även här finns det flera felvarianter som kan uppstå. Några vanliga fall som brukar uppstå är:

  1. Programmet "kraschar".
  2. Programmet verkar ha "fastnat".
  3. Programmet ger fel resultat.

Dessa tre fel angriper man på lite olika sätt och det finns även verktyg som man kan använda för att få hjälp med olika saker. Vi kommer dock inte att ge oss på att ta upp några speciella verktyg i denna kurs utan går på lite mer generella metoder för att hitta felen istället.

Fall nummer 1 (programmet "kraschar")

Om programmet kraschar beror det ofta på att man gjort något otillåtet med sina data eller att man tagit upp för mycket minne i datorn. Det är oftast i dena kurs att man försöker använda sig av data som inte ligger "inom programmet" utan att man går utanför någon form av gräns.

I Ada får man ofta felmeddelanden där det står något i stil med Data_Error, Constraint_Error, Name_Error, End_Error eller liknande. Programmet har dessutom avbrutits (kraschat). Ett specialfall som ni antagligen kommer att råka ut för är att programmet kraschar med det enda meddelandet "segmentation fault". Detta betyder i princip att ni har gjort en oändlig rekursion och då gäller det att fundera på var kan detta ske. Ofta är det så att man råkat anropa sig själv med meningen att anropa en inbyggd operator, men det finns fler fall.

Data_Error betyder ungefär att man har försökt hantera ett data som om det var av en annan datatyp än det verkligen var. T.ex. kan detta ske om man matar in (som användare av programmet) en sträng istället för ett heltal vid en "Get" för heltal.

Constraint_Error betyder att man ligger utanför någon gräns. Ett exempel på detta kan vara att man försöker stoppa in ett för stort tal i en Integer (t.ex. talet 256 i subtypen Small_Integer). Det kan också vara att man försöker komma åt data i en mer komplex variabel utanför de gränser som denna har. Mer om detta senare.

Oavsett vilka fel man fått har man ofta fått reda på var i programmet detta skedde. Oftast är det inuti ditt program och då anges också vilken rad som det hände på. Detta är det lätta fallet. Då kan man direkt hitta var det kraschat och kanske kan man utifrån detta finna felet man gjort i sitt program. Det kan tyvärr också vara så att programmet kraschat inuti något av Ada:s paket (t.ex. Ada.Text_IO) och då är det ju lite värre då du inte vet var i ditt program detta skett.

Hur gör man då? Jo, man kan skriva ut något som vi brukar kalla för "spårutskrifter". Små (extra) utskrifter (med Put_Line) som normalt inte skall finnas med i programmet, men som vi stoppat in för att se vilka rader i programmet som passeras. Skriver man ut t.ex. "A", "B", ... på skärmen på lite olika ställen i sitt program så vet man ju iallafall att man passerat den rad där "A" skrivs ut om detta syns på skärmen. Om inte "B" skrivs ut så har vi ju inte kommit fram dit och kan då dra slutsatsen att det hänt något mellan "A" och "B".

När man sen hittat stället där programmet kraschar och lyckats lösa sin uppgift tar man förstås bort sina språutskrifter så att de inte finns med när man skall leverera sitt program till kunden (oss lärare i denna kurs).

En annan variant man kan använda sig av är att man läser sin kod. Rad för rad och utför exakt samma saker som man skulle gjort när man kör programmet i datorn. Detta i kombination med att man antecknar allt man gör (t.ex. vad som finns i in- och utmatningsbuffertar och i olika variabler) gör att man antagligen (eller förhoppningsvis) hittar felet. Det tar dock ofta mer tid och kan kanske vara ett komplement när man vet var programmet kraschat för att förstå varför det kraschat.

Fall nummer 2 (programmet verkar ha "fastnat")

Om programmet verka ha fastnat (det kommer inte vidare). Vad kan detta bero på? Ja oftast beror det på att man har en "Skip_Line" för mycket eller att man har en "loop" som inte avslutas, men det finns fler saker som kan ställa till detta.

Hur gör vi i detta fall för att felsöka vårt program? Och hur får vi stopp på programmet?

Sista frågan först då den är lättast: Tryck "Ctrl-C" i terminalen där programmet körs. Det är det vanligaste sättet att avbryta sitt program.

Första frågan då? Hur letar vi reda på vart det fastnat? Jag skule vilja säga att det är samma tillvägagångssätt som för problemet då programmet kraschar. Skriv ut spårutskrifter så att du hittar stället där programmet fastnar.

Nu kan det vara så att du redan vet var i programmet du fastnat, men du förstår inte varför. Då skulle jag angripa problemet på samma sätt som för fall nummer 3 (se nedan).

Fall nummer 3 (programmet ger fel resultat)

Programmet kör, men det ger inte det förväntade resultatet. Det kan vara så att beräkningar men gjort eller villkor man har i sina "if"-satser är fel någonstans. Att det är något logiskt fel eller någon tankevurpa man gjort är dock det rimliga att anta. Börja inte gissa att det är fel på "gnatmake" eller datorn (även om det i ovanliga fall skulle kunna vara så, men det tror vi inte att ni råkar ut för i denna kurs).

Hur hittar vi detta då? Detta är det absolut svåraste fallet ni kommer att råka ut för och om man inte har verktyg att leta med är det ju lite besvärligt. Jag vill säga att man kommer väldigt långt även i detta fall med enkla spårutskrifter. Detta tillsammans med "lusläsning" av sin kod kan räcka i många fall.

Att förbättra detta kan man också göra. Man kan sätta sig och förklara hur det fungerar för sin labkamrat eller kanske labparet intill eller i sista hand assistenten. OBS! Det är ni som själva skall hitta felen för att ha en större chans att både lära er mer och även att klara er på själva tentan.

Nu kommer ytterligare en sak som kan göra att ni kommer att hitta felen ännu snabbare. Lite mer avancerade spårutskrifter. Det jag menar med detta är att man istället för att bara skriva "A", "B", "C" kan man skriva ut variablers värden. Skriver man ut värdet av variabel A får man ju mer information än att bara skriva olika tecken.

Man kan dessutom skriva ut flera variablers värden tillsammans vilket kan ge ännu mer information (den som även skriver ut variabelnamnet tjänar ofta på detta också).

En ännu mer avancerad utskrift kan göras om man skapar ett litet (eller stort) "spårutskriftsunderprogram" som skriver ut det man är intreserad av. Då kan man anropa detta på flera ställen utan att behöva skriva så mycket på varje ställe.

Vill man göra detta ännu mer avancerat kan man göra det, men vi börjar med detta och ger mer om det behövs (vilket jag inte tror).

En sammanfattning av tipsen

En bra början av felsökningsstrategier.

  1. Enkla spårutskrifter.
  2. Mer avancerade spårutskrifter.
  3. Läsa koden rad för rad och anteckna.
  4. Förklara för någon annan.

Det finns fler, men dem har vi inte pratat om. Vi kan dock lägga till ett par saker som alltid är bra, men som man skall ta till efter de ovan så att man inte alltid låter andra lösa problemen (det lär man sig inte på).

  • Sova på saken.
  • Fråga assistenten. :-)

Lycka till med felsökningarna och hoppas att detta givit något som gör att det går fortare!


Sidansvarig: Torbjörn Jonsson
Senast uppdaterad: 2017-09-04