[Tutorial] Debugging
#1

Aanleiding voor dit topic is omdat te veel mensen te weinig proberen hun problemen zelf op te lossen. Als je mijn lijst van gestarte topics na gaat, zul je zien dat ik haast geen vragen heb gesteld, en toch wel aardig kan scripten (naar eigen zeggen, maar feit is dat het nog steeds hoger is dan de gemiddelde gebruiker op deze fora.

Inleiding

Hallo daar! Deze tutorial gaat over het debuggen van je code. Nu zul je je misschien afvragen wat debuggen is. Simpel gezegd is debuggen nagaan waarom iets niet werkt. Iets kan in meerdere manieren 'niet' werken, ik zal de twee meest voorkomende aan bod brengen: (1) Verkeerde uitkomst/effect of (2) Crash/code wordt niet 'geroepen'.

Bij de verkeerde uitkomst of een verkeerd effect kan je je meerdere dingen voorstellen. Daarom zal ik het heel abstract houden: Je wilt dat je code iets doet. Er gebeurt inderdaad iets, maar dit is absoluut niet het gewenste effect!

Bij een crash, of niet-uitgevoerde code, gebeurt er (Zoals het idee al suggereerd) helemaal niks! Je zou bij dit stukje ook 'freeze' kunnen toevoegen, oftewel dat je server vast loopt door bijvoorbeeld in een nooit eindigende loop* te komen te zitten.

Ik denk dat je zelf wel het verschil tussen deze twee problemen kan ontdekken. Zo niet, dan raad ik het je af om docent Nederlands te worden. Ik denk dat we nu maar eens aan de slag moeten ! Wees wel op de hoogte dat ik heel kleine stukjes code gebruik.

Methode van aanpak

Om te debugging gebruik ik zelf bijna altijd de printf() functie/methode. Hiermee kan je heel makkelijk data naar de console sturen die voor jou van waarde kan zijn. Als je echt een server hebt gehost heb je hier natuurlijk weinig aan omdat je toch niet altijd naar die console kan kijken, dus is het altijd aangeraden te debuggen op je eigen, homehost pc.

Hier is dus een tip: Als je een probleem hebt en geen van beide manieren die ik aan orde breng in dit topic een uitkomst voor je bieden, kan je altijd nog zelf wat lopen prutsen met de printf() functie .

(1) Niet het gewenste effect

Voor dit stukje gebruik ik als voorbeeld de volgende (zelfgemaakte-) functie:
pawn Код:
stock Float:functie(Float:a, b)
{
  a += b;
  return a;
}
Zoals je waarschijnlijk kan opmaken zul je zien dat de waarde van 'b' bij 'a' wordt toegevoegd, en dit dan wordt terruggeven. Als ik nu eens dit script gebruikt:

pawn Код:
#include <a_samp>
stock Float:functie(Float:a, b)
{
  a += b;
  return a;
}

public OnFilterScriptInit()
{
    printf("%.3f", functie(1.0, 5));
    return 1;
}
Ik vul nu dus voor 'a' 1.0 in, en voor 'b' 5. Dat klopt, want a is een float en b een integer. Maar wat krijgen we terug? De waarde 1086324736.0! En dat was niet de bedoeling!

Dit is dus een voorbeeld waarbij de code wйl wordt uitgevoerd, maar het resultaat/effect ervan niet klopt. In dit geval zit de fout in onze 'functie', omdat dit de enige plaats is waar met deze waarden gewerkt wordt. Om dit te debuggen gaan we kijken waar het fout gaat. Dit doe je door te kijken wat de beginwaarden zijn en, steeds als er wat aan een waarde gewijzigd wordt, kijken of deze waarde juist veranderd is!

Als je dat snapt, dan zul je dit volgende wel begrijpen:
pawn Код:
stock Float:functie(Float:a, b)
{
  printf("Debug 1: a = %.3f && b = %i", a, b);
  a += b;
  printf("Debug 2: a = %.3f && b = %i", a, b);
  return a;
}
Het stukje "Debug 1" en "Debug 2" slaan erop dat het debug messages zijn, en de nummer slaan op welke verandering het is aan de waarden van de variabelen. "Debug 1" geeft dus de beginwaarden weer en "Debug 2" in dit geval de eindwaarden. Hoe je dit noteert in printf() maakt geen zak uit, zolang je er zelf maar wijs van kan worden.

Tip van Vince: Je kan ook het nummer van je script line opgeven in plaats van Debug 1, Debug 2, etc. (of wat je ook maar gebruikt). Op deze manier kan je heel makkelijk twee stukken code tegelijk debuggen!

Mijn debugmessages zijn als volgt:
Код:
Debug 1: a = 1.000 && b = 5
Debug 2: a = 1086324736.0 && b = 5
Bij 'Debug 2' zien we dat er iets mis is gegaan. Dat betekent dat we naar de voorgaande verandering moeten gaan. In dit geval is dat:
pawn Код:
a += b;
In deze regel zit dus de fout! Hier zal ik verder niet op ingaan, omdat deze tutorial voor jezelf is om te leren hoe je moet vinden wat en waar er in je script iets fout gaat. Als je toch nieuwsgierig bent, zie dan het einde van de tutorial**.

(2) Code wordt niet uitgevoerd

Ik ga nu wat vertellen over problemen die te maken hebben met bepaalde code die niet wordt uitgevoerd, of als je server vastloopt of zelfs crasht. Omdat ik totaal geen inspiratie heb zal ik gebruik maken van een never-ending loop*. Dit stukje is ook aan te raden als je server bijvoorbeeld crasht of als je een commando typt en dit 'SERVER: Unknown command' vertstuurt, zelfs als het commando bestaat (en mits het goed afgerond wordt).

Dit is mijn code:
pawn Код:
stock DingDong(dingelingeling)
{
  for(new b = 1000; b > 200; b++)
  {
    dingelingeling += 12;
  }
  return dingelingeling;
}
Deze code zal eeuwig doorgaan en hierdoor loopt je server vast! Ook dit gaan we debuggen met de printf() functie. Je zou ook gewoon print() kunnen gebruiken aangezien we hier net per se variabelen moeten 'checken'. Deze soort fouten debug je door achter elke regel een print() dingetje te zetten, met eventueel het 'debug id' of het lijnnummer. Het lijnnummer is aangeraden. Als je een loop gebruikt is het ook aan te raden het loop 'nummer' toe te voegen.

pawn Код:
stock DingDong(dingelingeling)
{
  printf("1")
  for(new b = 1000; b > 200; b++)
  {
    printf("2 loop id: %i", b);
    dingelingeling += 12;
  }
  print("3");
  return dingelingeling;
}
Nou zal je in je console een enorme spam vinden van '2 loop id: <nummer>'. Het is aangeraden dat als je met loops werkt een oog op je console te houden en deze snel te kunnen sluiten aangezien je meestal niet blij wordt van een logboek van 12 mb.

Aangezien deze code dus steeds dat nummer 2 liet zien in de console, weten we dat we ergens fout zitten in de loop.

<wordt vervolgd>

Afsluiting

Ik hoop dat deze tutorial je een beetje heeft geleerd hoe je je code moet debuggen, zodat je zelf kan uitvogelen waar de fout zit in je script. Dus nogmaals: Deze tutorial leert je niet over bepaalde fouten, functies of bepaalde dingen die je toe zou kunnen voegen aan je script, hij is er alleen maar voor zodat je zelf kan achterhalen wat je fout doet.
Ik ben er zeker van dat als je weet hoe je moet debuggen en de inhoud van de warnings en errors die de compiler geeft een beetje snapt, je 99% van al je problemen zelf op zou kunnen lossen.


Overige

In dit stukje staan nog enkele kleine dingetjes uitgelegd die met een asteriskje (*-teken) gemarkeert waren.

* nooit eindigende loop: Een loop waaraan een voorwaarde gesteld is die altijd klopt. Voorbeeld:
pawn Код:
new bool:c = true, d = 3;
while(c == true)
{
 d++;
}
Er gebeurt nooit wat met 'c', die blijft altijd 'true'. Deze loop eindigt nooit!

** Foute code: De code is fout omdat je een integer bij een float probeert op te tellen, en dat kan niet (1.0 + 5 kan trouwens wel dacht ik, heeft met de pre-processor te maken). Deze code is dus correct:
pawn Код:
stock Float:functie(Float:a, b)
{
  a = floatadd(a, b);
  return a;
}
Zoals gezegd, de rest komt later!
Reply
#2

Njah... ik debug ook wel redelijk veel en zeker nu in me derby gamemode waar ik lastige problemen heb ... maar nog altijd geen oplossing :-/ Maar het is een goed tut
Reply
#3

Eindelijk iemand die er aandacht aan besteed
Ziet er zeker netjes uit, en zal zeker mensen gaan helpen
Reply
#4

Dit is goed! Als je het even naar het Engels vertaalt of zo, dan hebben die andere noobs er ook nog wat aan. Kleine tip trouwens; Als ik debug code uitvoer, dan zet ik ook altijd het line nummer in m'n printf zodat ik dat nadien makkelijk kan terugvinden.
Reply
#5

Bedankt voor all reacties zo ver .

Quote:
Originally Posted by Vince
Посмотреть сообщение
Dit is goed! Als je het even naar het Engels vertaalt of zo, dan hebben die andere noobs er ook nog wat aan.
Dat zal ik doen zodra ik deze tutorial afgerond heb!

Quote:
Originally Posted by Vince
Посмотреть сообщение
Kleine tip trouwens; Als ik debug code uitvoer, dan zet ik ook altijd het line nummer in m'n printf zodat ik dat nadien makkelijk kan terugvinden.
Da's natuurlijk ook een goed idee, die zal ik er wel even bij zetten .
Reply
#6

Mooie tutorial, alles netjes en vooral overzichtelijk uitgelegd. Heel nuttig, want idd er zijn teveel vraagtopics :P

Btw, misschien kan je me helpen hiermee:

EDIT: Stom, khad geen delimiter aangegeven bij sscanf. Dat komt er nu van als je in je schoolpauze gaat scripten :/
Reply
#7

Heel handig, ik blijf me verbazen over dat sommige mensen dit soort simpele dingen gewoon niet kunnen begrijipen. Misschien ook nog een tip, veel code kan je in een if statement zetten, om te kijken wat het 'returned' goed voorbeeld is 'sscanf' normaal laten mensen die lijn gewoon ze gang gaan, bijvoorbeeld met de informatie opdelen in variables, vaak als het dan niet werkt weten ze niet waar ze moeten kijken, hadden ze die lijn nou in een if statement gezet, dan kan je het zo maken dat je direct weet waar het probleem zit, en als je het ook nog goed uitprint, zie je ook gelijk waarom. En dat allemaal zonder het script open te maken, en een eeuwigheid te debuggen.

pawn Код:
if(sscanf(stringding))  
{
    printf("Appereantly you fucked up, and sscanf couldn't handle it, this is what it tried to parse: %s", stringding);
}
else
{
    // de code
}
Heerlijk dat scripten in dit kleine kud menutje.
Reply
#8

Nee, dat weet ik niet de taal, maar ik ****** vertaald = D.
pawn Код:
new count
printf ("%d", count++);
En gewoon doorgaan, zoals:
pawn Код:
printf ("Debugging / help commando %d", count++);
Reply
#9

Quote:
Originally Posted by playbox12
Посмотреть сообщение
Heel handig, ik blijf me verbazen over dat sommige mensen dit soort simpele dingen gewoon niet kunnen begrijipen. Misschien ook nog een tip, veel code kan je in een if statement zetten, om te kijken wat het 'returned' goed voorbeeld is 'sscanf' normaal laten mensen die lijn gewoon ze gang gaan, bijvoorbeeld met de informatie opdelen in variables, vaak als het dan niet werkt weten ze niet waar ze moeten kijken, hadden ze die lijn nou in een if statement gezet, dan kan je het zo maken dat je direct weet waar het probleem zit, en als je het ook nog goed uitprint, zie je ook gelijk waarom. En dat allemaal zonder het script open te maken, en een eeuwigheid te debuggen.

pawn Код:
if(sscanf(stringding))  
{
    printf("Appereantly you fucked up, and sscanf couldn't handle it, this is what it tried to parse: %s", stringding);
}
else
{
    // de code
}
Heerlijk dat scripten in dit kleine kud menutje.
Ik kan dat wel begrijpen hoor, bij commands doe je eigelijk precies hetzelfde. Ik had er nog nooit over nagedacht dat je sscanf zo kan gebruiken voor debugging. Maar inderdaad, das wel handig.

EDIT: Ik wil geen regels overschrijden, maar volgensmij bugt die post-time counter. Hij zegt net drie keer dat ik 120 seconden moet wachten tot mn volgende post, terwijl ik nog niks gepost had. Weird :X
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)