GPT- föreläsning 10 För en vecka sedan Problemlösning på lägre nivå kan sortera funktioner Förra gången poparoramometoterorövoverorfoförorinongog Denna gång Olika typer av fel Felsökning och felsökningsverktyg
Fel En grov förenkling är att säga att vi har tre olika typer av fel i våra program syntaxfel exekveringsfel logiska fel
Fel - syntax Syntaxen för ett språk är de ord som tillhör språket samt språkets grammatik I fallet med naturliga språk pratar vi också om språkets semantik (vad det betyder) och pragmatik (hur det används) Meningen Pelle kör ett tomt glass är (nästan) syntaktiskt korrekt, men semantiskt lite galen Meningen Är det inte mörkt här inne? Signalerar semantiskt att det handlar om en fråga om ljusnivå, men pragmatiskt handlar det om att uttrycka en önskan att tända ljuset
Fel - syntax I formella språk, som tex C, är syntax och semantik ytterst väldefinierade Detta för att man maskinellt skall kunna tolka språket utan ambiguiteter, dvs tvetydigheter Programspråket C definieras i standard ANSI C (de första utkasten från 1983) Nuvarande standard är från 2000 och heter följaktligen C99
Fel - syntax I C finns det reserverade ord ord som har speciell betydelse och som inte får användas till annat än vad standarden säger Exempel på reserverade ord är for, while, do if, else, switch, case, default break, continue, goto, return int, char, float, void, short, unsigned, sizeof include, define =, +, -, *, /, %, ++, -= Vi har dessutom olika satser som bygger på de reserverade orden tilldelning if-else satsen for-satsen while-satsen do-satsen switch-satsen break-satsen Satser avslutas med ;
Fel - syntax En sats kan dessutom bestå av uttryck Olika satser kan kombineras i olika block Och block kan grupperas i funktioner Poängen är att hela språket definieras med tydliga regler, en så kallad grammatik
Fel - syntax När kompilator skall översätta C- kod (som människor förstår) till maskinkod (som datorer förstår) börjar den med att parsa programmet En parsning innebär att tecknen grupperas i meningsfulla enheter utifrån språkets grammatik En sådan meningsfull enhet kallas token Parsningen utförs av en lexikalanalysator Tokens organiseras i parseträd svarande mot grammatiken i språket
Fel - syntax Redan vid parsningen kan lexikalanalysatorn konstatera vissa fel Det kan tex vara Tecknen som analysatorn hittar i källkoden matchar inte definitionerna av något token Det går inte att översätta samlingen av tokens till ett träd Kompilatorn konstaterar att vi fått ett syntaxfel 12 + 3*x 12 + x*3 + 3(12+3*x)
Fel - syntax Kompilatorn kan alltså själv hitta syntaxfel Kompilatorn markerar var i koden felet upptäcks Detta behöver inte nödvändigtvis vara exakt där felet finns Vid felsökning av syntaxfel börja alltid uppifrån i filen rätta till fel och kompilera om innan du fortsätter leta Många syntaxfel ger mängder av följdfel eftersom kompilatorn helt enkelt har tappat tråden #include<stdio.h> int main(void){ printf("hello World") } Syntax error before '}' token
Kom ihåg: bara för att koden går genom kompilatorn utan varningar betyder inte att den är felfri!
Fel - exekveringsfel Exekveringstiden för ett program definieras som tiden från det att operativsystemet lämnar över kontrollen till mainfunktionen tills det att main-funktionen returnerar Fel som får programmet att avsluta utan normal retur till operativsystemet kallas exekveringsfel Exekveringsfel beror oftast på att programmet nyttjar systemresurser felaktigt Exempel på systemresurser är minnet olika IO-enheter filer Det är operativsystemet som ansvarar för den interna säkerheten på datorn
Fel - exekveringsfel En variant av exekveringsfel är om programmet går in i en oändlig loop Detta beror i princip uteslutande på att slutvillkor i en iterationssats (for eller while) är fel basfallet saknas eller missas i rekursion Vid iterationer och rekursioner skall man alltid kontrollera att det finns ett stoppvillkor/basfall som inte kan missas att varje iteration tar oss ett steg närmare stoppvillkoret Dubbelkolla att > och < används rätt att loopvariabeln uppdateras
Fel - exekveringsfel Minnesfel är kanske de vanligaste exekveringsfelen vi stöter på Minnesfel beror på att vi försöker läsa eller skriva till minne som vi inte har tillträde till Exekveringsfel resulterar i meddelanden av typen segmentation fault
Fel - exekveringsfel Vanligaste orsakerna är att vi indexerar oss utanför arrayer att vi glömmer adressoperatorn (&) att minnesallokering inte lyckats att vi indexerar pekare som inte allokerats #define N 532476523234 int a[n]; int *a; a[10]=1; int a; scanf( %d,a); int i,j,n=100,a[n]; for (i=0;j<n;i++) a[i]=i;
Fel - exekveringsfel Exekveringsfel kan vara svåra att hitta eftersom vi oftast bara får reda på att nått är fel, inte var Felsökningsstrategin blir i det här fallet att börja från början av main och lägga in utskrift/stop vid varje funktionsanrop och se vilken funktion det är som kraschar Gå sedan till början den funktionen och upprepa samma procedur Kontrollera speciellt de fyra orsakerna på förra sliden
Våra första felaktiga C-program Hitta felen i DEBUG1.c
Fel - logiska Logiska fel är när man tänkt/gjort fel som resulterar i kod som är syntaktiskt korrekt och inte resulterar i exekveringsfel Vi får med andra ord ingen varning vid kompilering, ingen segmentation fault, utan helt enkelt fel resultat De felaktiga resultaten kan vara predikterbara slumpmässiga Logiska fel kan i sin tur delas upp i olika fel Modellfel Slarvfel Fel kopplade till den ändliga aritmetiken i datorn, dvs avrundningsfel trunkeringsfel
Fel - logiska Modellfel är när vår modell av verkligheten inte stämmer överens med verkligheten Detta kan bero på att vi gjort medvetna förenklingar missförstått problemet Modellfel är svårt att felsöka bort i befintlig kod, utan vi måste börja om med en bättre ansats Exempel på modellfel Om vi antar att slumpmässig längd (i cm) på vuxna personer ges av L=rand()%50 +150; Om vi beräknar att jorden är ett klot med radien r och ytarean A=4*3.1415*r*r
Fel - logiska Under avdelningen slarvfel hittar vi saker som användning av tilldelning i stället för likhetstest felaktig evaluering av uttryck att returnera arrayer från funktioner att använda icke initierade variabler att placera avslutande } fel off-by one fel att inte hantera extremvärden av olika slag allt för smart pekararitmetik att vi antar att indata har visst format/egenskaper utan att kontrollera
Fel - logiska Slarvfel kan undvikas genom att vara noggrann med indentering undvika att använda allt för komplicerade one-liners uttryck kompilera med Wall flaggan satt dela upp komplexa uttryck i mindre delar alltid sätta parenteser och måsvingar i matchande par kontrollera att så fort en variabel finns på höger sida om = så skall den vara initierad dubbelkolla användning av == i villkor testa extremfallen, det är då off-by one felen tittar fram aldrig testa med likhet mot en float
Fel - logiska Vi har tidigare sett att all data som lagras i en dator har en ändlig representation Detta får till följd att vi inte kan lagra godtyckligt stora tal I exemplet med jodens ytarea A=4*3.141592654*r*r får den ändliga representationen följande fel: tal med godtycklig precision r är ett beräknat värde som innehåller fel av olika slag approximationen av π är ändlig de aritmetiska beräkningarna kommer att resultera i avrundningar
Fel - logiska Vissa effekter av den ändliga representationen blir tydliga först efter lång tid tex små, men systematiska fel, som avrundningsfel Ett exempel är börsen i Vancouver som 1982 räknade om sitt index till 1000.000 Efter varje transaktion uppdaterades index Efter 22 månader hade index fallit till 520 Det visade sig att istället för att avrunda värdena så trunkerades värdena efter varje transaktion I efterhand kunde man konstatera att index skulle vara 1098.892 med korrekta avrundningar
Fel - logiska Ett annat exempel var styrsystemen till amerikanska Patriot missiler under Gulfkriget 1991 En timer i missilen startade när styrdatorn slogs på Timern räknade upp med tiondels sekunder och måste multipliceras med 1/10 för att ge tiden i sekunder 1/10 decimalt motsvarar 0.0001100110011001100110011001100... binärt När det binära talet lagrades i ett 24 bitars register introducerades ett fel på 0.0000000000000000000000011001100... binärt (dvs ca 0.000000095 decimalt per 1/10 sekund) Efter 4 dygn i drift var felet 0.34 sekunder En Scudmissil har en hastighet av ca 1676 m/s vilket ger att tidsfelet motsvarar 569 meter
Sammanfattning Nyckelord: fel, felsökning, typer av fel, söka med printf, Sammanfattande mening: Du är fel och du skall bort! The computer says NO!