Lekce 8 - Visual Studio - Debugging
V minulé lekci, Visual Studio - Snippety, jsme se věnovali snippetům.
V dnešním Visual Studio tutoriálu si ukážeme debuggování C# .NET aplikací. Na praktických příkladech si osvojíme základní možnosti debuggování. Ukážeme si například jak pozastavit program, nahlížet do obsahu proměnných a podobně.
Debugging
Debugging je proces odstranění chyb v programu, které obvykle nejsou na první pohled vidět. Někdy se o něm hovoří také jako o ladění programu.
Proč a kdy debugovat?
Chyby v programu se většinou projevují tím, že je v nějaké proměnné nesprávná hodnota, která pak zapříčiní nefunkčnost programu. Určitě jste se již dostali do situace, kdy váš program nefungoval správně. Možná jste prováděli nějaké zdlouhavé kontrolní výpisy různých proměnných, abyste zjistili, kde je ještě vše správně a kde jsou již nesprávné hodnoty.
Chybu lze ovšem obvykle najít mnohem snadněji pomocí debuggování. Program obvykle spustíme ve speciálním režimu, kde máme dovoleny určité "cheaty", jako např. program pozastavovat a nahlížet do obsahu proměnných. Právě to se dnes naučíme.
Není ovšem pravda, že debugger používáme jen když program nefunguje! Naopak, používáme jej co nejvíce to jde a to i třeba pro kontrolu správnosti na kritických místech.
Krokování cyklu
Mějme jednoduchý cyklus, ve kterém budeme vypisovat čísla od
0
do 9
:
{CSHARP_CONSOLE}
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Číslo: " + i);
}
{/CSHARP_CONSOLE}
Výstup z konzole:
Konzolová aplikace
Číslo: 0
Číslo: 1
Číslo: 2
Číslo: 3
Číslo: 4
Číslo: 5
Číslo: 6
Číslo: 7
Číslo: 8
Číslo: 9
Jak můžeme vidět, program funguje korektně. Přesto si jej zkusíme oddebuggovat, než se pustíme na nefunkční kód.
Breakpointy
Breakpoint je základní stavební kámen při debuggování. Je to místo označující řádek, na kterém se program zastaví. Nám, jako programátorům, se v tu chvíli zobrazí kompletní kontext programu. Například, co je v tu chvíli kde uloženo. Protože program stojí, můžeme si vše snadno zkontrolovat.
Přidání breakpointu
Nyní se naučíme vkládat breakpointy a zastavovat na nich program. Ve Visual Studiu se breakpoint na daný řádek vkládá kliknutím do prostoru vlevo vedle čísla řádku. Breakpoint pak poznáme podle červeného kolečka. Vložme tedy breakpoint na řádek, kde se vypisuje číslo do konzole:

Debug režim
Breakpoint máme přidaný. Když však program nyní spustíme, nic zvláštního se nestane. Aby se program opravdu zastavil, je potřeba ho spustit ve speciálním debuggovacím režimu. K tomu slouží tlačítko ikony spuštění s názvem našeho programu (na obrázku níže Debug):

Alternativně lze spustit debuggování klávesou F5.
Klikneme tedy na výše zmíněné tlačítko. Program se spustí a až narazí na náš breakpoint, tak se zastaví:

Řádek označený breakpointem se podbarvil žlutě. To znamená, že breakpoint je dosažitelný. Zároveň se nám v horním menu otevřela nová záložka pro debuggování a ve spodní části okna Locals a Call Stack. Pojďme si vše vysvětlit.
Okno Locals
V levém spodním okně, na obrázku zvýrazněném zeleně, vidíme seznam všech aktuálně viditelných proměnných a jejich hodnoty. Hodnoty lze změnit.
Alternativně je možné zjistit hodnotu proměnné tak, že na ni v okně Program.cs najedeme kurzorem myši.
Okno Call Stack
V pravém spodním okně, na obrázku zvýrazněném oranžově, vidíme zásobník volání všech metod, které se zavolaly před zastavením na breakpointu.
Záložka pro debuggování
V horním menu Visual Studia se nejprve zaměříme na tlačítka pro ovládání debuggování, které na obrázku výše jsou identifikovaná identifikátory 1, 2, 3 a 4:
1 - Continue - uvolní program z
breakpointu, nechá ho běžet a případně ho zastaví o další
breakpoint,
2 - Break All Ctrl + Alt +
Break - pozastaví celý program a čeká na
opětovné spuštění,
3 - Stop Debugging Shift + F5 -
ukončí debuggování,
4 - Restart Ctrl + Shift + F5
- zahájí debuggování od začátku.
Krokování
Ze záložky pro debuggování si nyní vysvětlíme tlačítka pro ovládání krokování, kterými můžeme nechat program pokročit na další řádek a zase ho zastavit. Tyto tlačítka na obrázku výše jsou identifikovaná identifikátory A, B, C a D:
A - Show next statement Alt + Num* -
přeskočí na další příkaz, který je označen žlutou
šipkou a je žlutě podbarvený,
B - Step into F11 - skočí na
první řádek volané metody z aktuálního řádku,
C - Step over F10 - vykoná
příkaz/volání metody na aktuálním řádku a přejde na další řádek,
kde se zastaví,
D - Step out Shift + F11 -
vystoupí z aktuálně krokované metody.
Dokončení krokování cyklu
Vraťme se k našemu běžícímu debuggování. My se nacházíme v cyklu,
kde pouze vypisujeme jednu hodnotu. Nicméně i tak můžeme pomocí tlačítka
Step Over krokovat vypisování hodnot do konzole,
sledovat posun běhu programu v cyklu a změnu hodnoty
proměnné i
v okně Locals. Nakonec ukončíme
debuggování našeho příkladu na krokování cyklu stisknutím tlačítka
Stop Debugging.
Příklad - Oprava programu
Nakonec si dáme příklad opravdu k procvičení debuggování
Identifikace správného chování programu
Mějme dva vnořené cykly, které by měly vypsat malou násobilku:
{CSHARP_CONSOLE}
for (int j = 1; j <= 10; j++)
{
for (int i = 1; j <= 10; j++)
{
Console.Write(i * j + " ");
}
Console.WriteLine();
}
{/CSHARP_CONSOLE}
Výsledek by měl vypadat takto:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Identifikace chybného chování programu
Problém ale je, že se vypíší pouze čísla od 1
do
10
:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Chybu budeme samozřejmě chtít najít a opravit za pomoci breakpointů a krokování.
I když uvidíte chybu na první pohled, stejně si to odkrokujte! Ve složitějších aplikacích chyba snadno vidět nebude a debuggování bude nutné.
Debuggování
Očekáváme, že vnější cyklus se provede 10x, zatímco vnitřní cyklus
se provede celkem 100x. Vložíme breakpoint na řádek s
vnějším for
cyklem:
for (int j = 1; j <= 10; j++)
A spustíme program v debuggovacím režimu. Bude nás zajímat, jak se
proměnné i
a j
zvyšují. Tlačítkem Step
into budeme postupně procházet přes oba cykly a pozorovat hodnoty
proměnných i
a j
v okně Locals. Vnější
cyklus pracuje s proměnnou j
, která by se měla změnit pouze
10x. Vnitřní cyklus pracuje s proměnnou i
, která by se měla
při každé změně j
upravit 10x.
Identifikace a oprava chyb
Postupným krokováním však zjistíme, že vnitřní cyklus inkrementuje
proměnnou j
namísto i
. Ve vnitřním cyklu upravíme
j++
na i++
a program opět spustíme v debuggovacím
režimu:
for (int i = 1; j <= 10; i++)
Krokujeme opět tlačítkem Step into. Sledujeme proměnnou
i
. Po čase začne nabývat neočekávaných hodnot, které se
neustále o jedničku zvyšují. Pokud teď necháme program běžet, začne se
nám počítač sekat. To je z důvodu, že ve vnitřním cyklu je podmínka,
která nikdy nebude splněna.
V cyklu for (int i = 1; j <= 10; i++)
máme proměnnou
i
, kterou už správně inkrementujeme, ale
podmínka je špatná. Proměnná i
se
inkrementuje, dokud platí j <= 10
. Tato podmínka nikdy nebude
splněna, protože proměnná j
se modifikuje pouze ve vnějším
cyklu. Opravíme podmínku vnitřního cyklu z j <= 10
na
i <= 10
:
{CSHARP_CONSOLE}
for (int j = 1; j <= 10; j++)
{
for (int i = 1; i <= 10; i++)
{
Console.Write(i * j + " ");
}
Console.WriteLine();
}
{/CSHARP_CONSOLE}
Testování opraveného programu
Nyní spustíme program bez debuggování tlačítkem Start without Debugging Ctrl + F5 a necháme program doběhnout. Výsledkem již je očekávaná malá násobilka:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
V další lekci, Visual Studio - Pokročilý debugging, si rozšíříme znalosti debuggování ve Visual Studiu. Ukážeme si užitečné nástroje jako např. krokování, podmínkové breakpointy a další.