Rozdział 3.
Debuggowanie: gdy aplikacja nie działa
W tym rozdziale:
Czym jest debuggowanie
Możliwości, które powinien posiadać każdy debugger
Korzystanie z debuggera wbudowanego w Yisual Studio
Korzystanie z informacji w oknie debuggera
Korzystanie z punktów przerwań i pracy krokowej przy śledzeniu błędów
ZarzÄ…dzanie debuggowaniem aplikacji wielowÄ…tkowych
Zastosowanie podstawowych technik debuggowania
Wykorzystanie śledzenia MFC
Zastosowanie zdalnego debuggowania
Gdy piszesz program w jakimkolwiek języku, praktycznie nie ma możliwości, by od razu był wolny od błędów. Podczas pisania programów zdarzają się dwa rodzaje błędów: błędy składniowe oraz błędy logiczne. Błędy składniowe zwykle są dużo prostsze i najczęściej o wiele łatwiejsze do zlokalizowania niż błędy logiczne. W rzeczywistości, podczas kompilowania programów napisanych w Visual C++ kompilator sam wykryje wszystkie błędy składniowe wewnątrz kodu programu. W takich przypadkach odmówi stworzenia pliku wykonywalnego, gdyż nie potrafi skompilować programu zawierającego tego typu błędy.
Z drugiej strony, błędy logiczne nie są tak łatwe w wyśledzeniu i usunięciu. Zlokalizowanie błędu logicznego może być stosunkowo łatwe lub krańcowo trudne. Na przykład, poniższy błąd logiczny jest stosunkowo prosty:
cout « "To jest pierwsza linia." « "To jest druga linia.";
Ten kod wyświetli obie linie tekstu w tym samym wierszu. Usunięcie tak prostego błędu logicznego jest względnie łatwe. Jednak rozwiązanie błędu logicznego podobnego do następnego może być już znacznie trudniejsze:
if(a!=c)
cout « "A nie jest równe C"; cout « "A musi być równe C!";
Podczas wykonywania programu zawsze zostanie wyświetlony tekst
A musi być równe C!
Błędem logicznym jest brak nawiasów klamrowych obejmujących dwie instrukcje wyjścia. Jednak nawet ten błąd jest prosty w porównaniu z błędami logicznymi, które możesz popełnić w złożonych aplikacjach Windows. Na szczęście Yisual C++ zawiera doskonały, zintegrowany symboliczny debugger. Debugger w Yisual C++ posiada wiele wydajnych i użytecznych funkcji, takich jak Just-In-Time debugging (możliwość debuggowania programów, które uległy załamaniu po uruchomieniu poza Visual Studio) czy zdalny debugging. Debugger jest także w pełni zintegrowany z innymi elementami Visual Studia, takimi jak przeglądarka czy edytor kodu źródłowego.
Gdy staniesz przed zadaniem określenia wąskiego gardła ograniczającego wydajność programu - bardzo specyficznym rodzajem błędu logicznego - użyjesz jednak innego narzędzia, którym jest Profiler. Profiler, zaprojektowany specjalnie do analizy wydajności programów, zostanie opisany w następnym rozdziale.
Co każdy debugger posiadać powinien
To oczywiste, że debuggowanie aplikacji może być procesem prostym lub bardzo złożonym. Wraz ze wzrostem stopnia złożoności i rozmiarów aplikacji, wzrasta również potrzeba posiadania wydajnego narzędzia do debuggowania. Jako regułę należy przyjąć, że debugger posiada przynajmniej cztery następujące możliwości:
Åšledzenie
Punkty wstrzymań
PodglÄ…d zmiennych
Zmiana wartości
Prawdopodobnie najważniejszą funkcją debuggera jest możliwość śledzenia (ang. tracę). Dzięki śledzeniu można dokładnie wiedzieć, która część programu jest aktualnie wykonywana. W Visual C++ masz do wyboru kilka możliwości śledzenia programu, od wykonywania osobno kolejnych linii kodu aż do wykonywania dużych części programu i do momentu dojścia do określonego miejsca w kodzie.
Jak się zapewne domyślasz, wykonywanie programu linia po linii może być bardzo żmudne, zwłaszcza w przypadku gdy wiesz, że pewna część kodu jest prawidłowa. Nawet mały program (powiedzmy o tysiącu linii) może zająć wiele czasu przy przechodzeniu go krok po kroku w celu przeanalizowania kilku podejrzanych linii. W przypadku większych programów, perspektywa przejścia krokowo przez tysiące linii kodu - co trwa godziny - w celu dojścia do krótkiej procedury, która działa nie tak jak trzeba, jest wprost przerażająca. Z powodu rozmiaru wielu plików programów zdolność do zatrzymania wykonania programu w wyznaczonym miejscu lub po wystąpieniu określonego warunku jest drugą najważniejszą możliwością każdego debuggera. Większość debugge-rów obsługuje zatrzymywanie wykonania programów przez zastosowanie tak zwanych punktów wstrzymania (ang. breakpoint).
Oczywiście, obserwowanie przejścia aplikacji przez serię instrukcji i analizowanie, która ścieżka wykonania prowadzi do błędu, jest doskonałą techniką debuggowania. Jednak cenne, a nawet cenniejsze niż zrozumienie istoty błędu, jest zrozumienie dlaczego on występuje. Dobry debugger powinien umożliwić Ci przejrzenie bieżących wartości zmiennych w programie, z uwzględnieniem kontekstu i zasięgu odpowiednich dla aktualnego miejsca wykonywania programu.
Gdy dowiesz się, w jaki sposób błędna wartość zmiennej wpływa na program (przekroczona wartość, wartość niezdefiniowana itd.) lub powoduje wyjątek, zwykle będziesz mógł zmienić jej wartość na bieżąco - aby zapewnić, że wartość z poprawnego zakresu także nie powoduje błędu. Tak więc czwartą cenną cechą debuggera jest możliwość zmiany wartości lub zawartości zmiennych podczas wykonywania programu, dzięki czemu możesz sprawdzić reakcję programu na szeroki zakres wartości zmiennych, bez konieczności ponownego uruchamiania programu z różnymi zestawami danych.
Jak dowiesz się w dalszej części rozdziału, zintegrowany z Yisual Studio debugger posiada wszystkie wymienione możliwości oraz wiele innych, które już nieraz sprawdziły się jako wydajny pakiet do debuggowania aplikacji.
Debugger zintegrowany z Visual Studio
Visual C++ i powłoka Visual Studia uruchamiaj ą zintegrowany debugger za każdym razem, gdy uruchamiasz aplikację w trybie debuggowania. Jak zobaczysz w dalszej części rozdziału, powłoka uruchamia zintegrowany debugger także wtedy, gdy klikniesz przycisk Debuggowanie w oknie komunikatu o wykonaniu przez program nieprawidłowej operacji. Aby uruchomić aplikację w trybie debuggowania wewnątrz Visual C++, w menu Build, w podmenu Start Debug, wybierz polecenie Go, Step Into lub Run to Cursor. Jednak zanim uruchomisz debugger, upewnij się, że aplikacja została skompilowana tak, aby zawierała informacje potrzebne do debuggowania.
Przygotowanie aplikacji do debuggowania
Jak wykazaliśmy w poprzedniej sekcji, aby symboliczny debugger mógł poprawnie funkcjonować i abyś mógł korzystać z informacji debuggowania w swoim projekcie Yisual C++, musisz poinstruować kompilator aby zawarł w pliku wykonywalnym informacje
debuggera. Jeśli aplikacja, którą chcesz przeanalizować, jest aplikacją MFC stworzoną oryginalnie przez AppWizarda, istnieje duża szansa, że AppWizard stworzył już w projekcie konfigurację do debuggowania i uczynił ją konfiguracją domyślną.
Jeśli jednak sam stworzyłeś projekt od początku lub nie jest on aplikacją MFC, musisz samodzielnie stworzyć konfigurację do debuggowania. Służy do tego okno dialogowe Project Settings (ustawienia projekt). W tym oknie musisz ustawić odpowiednie opcje kompilatora i linkera. Gdy to zrobisz, będziesz mógł przeanalizować program za pomocą debuggera wbudowanego w Yisual Studio.
Aby ustawić opcje kompilatora, w menu Project wybierz polecenie Settings. Yisual Studio wyświetli okno dialogowe Project Settings. Kliknij zakładkę C/C++. W oknie dialogowym pojawią się ustawienia projektu odnoszące się do języka C lub C++. Po lewej stronie okna, z rozwijanej listy, wybierz konfigurację Win32 Debug. Z rozwijanej listy Category wybierz kategorię General (ogólne). Aby włączyć dla projektu debuggowanie, musisz zmodyfikować dwa ustawienia. Po pierwsze, z rozwijanej listy Debug Info (informacje dla debuggowania) wybierz pozycję Program Database for Edit and Continue. Po drugie, z rozwijanej listy Optimizations (optymalizacje) wybierz pozycję Disable (debug) (wyłącz dla debuggera). Okno dialogowe z włączonymi ustawieniami debuggowania przedstawia rysunek 3.1.
Jeśli chcesz skorzystać z wbudowanej w Visual Studio przeglądarki kodu źródłowego, możesz włączyć także opcję Generate browse info (generuj informacje przeglądania). AppWizard automatycznie wyłącza tę opcję w celu skrócenia czasu kompilacji.
Jeśli korzystasz z kompilatora w linii poleceń lub z własnego pliku makefile, możesz zechcieć ręcznie ustawić opcje debuggowania. Aby wyłączyć optymalizację, użyj opcji /od kompilatora. Aby włączyć generowanie informacji dla debuggera, użyj opcji /zi. Więcej informacji na temat parametrów linii poleceń znajdziesz w pliku pomocy Visual C++.
Kolejnym ustawieniem, o którym należy pamiętać przygotowując aplikację do debuggowania, jest opcja powodująca linkowanie projektu z biblioteką czasu wykonania C w wersji dla debuggowania. Aby poinstruować kompilator, aby użył tej biblioteki, z rozwijanej listy Category wybierz pozycję Code Generation (generowanie kodu). Następnie z rozwijanej listy Use run-time library wybierz bibliotekę debuggera odpowiadającą Twojej aplikacji. Ustawienia generowania kodu, wraz z dostępnymi rodzajami bibliotek czasu wykonania, zostały przedstawione na rysunku 3.2.
Także w tym przypadku możesz ustawić odpowiednie opcje w linii poleceń. Służy do tego opcja kompilatora /M. Aby wybrać opcję biblioteki Debug DLL, wpisz parametr linii poleceń /MDd. Aby wybrać opcję biblioteki Debug Single-Threaded, wpisz parametr linii poleceń /MLd. Na koniec, aby wybrać opcję biblioteki Debug Multithreaded, wpisz w linii poleceń parametr /MTd.
Gdy tworzysz projekt do debuggowania, musisz zmodyfikować także ustawienia programu łączącego (linkera), tak aby projekt mógł zostać poprawnie skompilowany i połączony. Także w tym przypadku możesz skorzystać z okna ustawień projektu. Kliknij zakładkę Link i z rozwijanej listy Category wybierz pozycję General. Aby włączyć generowanie informacji dla debuggowania, włącz opcję Generate debug info. Wygląd okna dialogowego po ustawieniu opcji linkera dla trybu debuggowania przedstawia rysunek 3.3.
Tak jak w przypadku opcji kompilatora, także opcje linkera mogą zostać podane w linii poleceń. Aby włączyć generowanie informacji dla debuggera, w linii poleceń programu łączącego zastosuj parametr /debug.
Korzystanie z debuggera podczas działania aplikacji
Po przekompilowaniu aplikacji z ustawieniami dla trybu debuggowania możesz uruchomić ją w trybie debuggera, korzystając z dowolnego polecenia (z wyjątkiem Attach to Process) w podmenu Start Debug w menu Build.
Sposób działania debuggera możesz określić w oknie ustawień projektu. Na zakładce Debug tego okna dialogowego możesz określić różne aspekty działania programu w trybie debug-gowania. Jednym ze szczególnie interesujących pól na zakładce Debug jest pole Executable for debug session (program wykonywalny dla sesji debuggera). Możesz go użyć przy de-buggowaniu projektów bibliotek łączonych dynamicznie (DLL). Jednak zamiast podawać nazwę DLL-a, powinieneś podać nazwę ładującego i odwołującego się do danej biblioteki DLL. Na przykład, aby zbudować kontrolkę ActiveX (która jest szczególnym rodzajem biblioteki DLL), jako programu wykonywalnego dla sesji debuggera możesz użyć dostarczanego wraz z Yisual C++ programu tstcon32.exe. Rysunek 3.4 przedstawia okno dialogowe ustawień projektu po wybraniu testowego programu tstcon32.exe.
Gdy rozpoczynasz sesję debuggera, w oknie Visual Studia mogą pojawić się różne okna debuggowania, zależnie od wybranych wcześniej ustawień. Oprócz tego znikają inne, zwykle widoczne okna, na przykład okno widoku projektu. Zmienia się także pasek menu Visual Studia - zamiast menu Build pojawia się menu Debug.
Aplikacja wybrana do debuggowania rozpoczyna działanie i jest wykonywana aż do momentu, w którym osiągnie punkt wstrzymania ustawiony przez debugger lub kiedy w menu Debug wybierzesz polecenie Break (przerwij). W tym momencie działanie aplikacji zostaje wstrzymane.
Okna debuggowania
Podczas sesji debuggera Visual Studio prezentuje informacje debuggowania w kilku specjalnych oknach. Jeśli Visual Studio akurat nie wyświetla żadnego z tych okien, możesz przejść do menu View (widok) i wyświetlić te okna, których potrzebujesz. Okna omawiane w tej sekcji możesz otworzyć jak normalne okna lub jako okno dołączone do krawędzi głównego okna Visual Studia. Jeśli dołączysz okno do krawędzi, wystąpi ono także w menu podręcznym - wyświetlanym przez Visual Studio w momencie, gdy klik-niesz prawym przyciskiem myszy pusty obszar dowolnego paska narzędzi.
Okna kodu źródłowego są zwykłymi oknami edytora kodu. Jednak podczas sesji debuggera w menu podręcznym są dostępne także specjalne funkcje. W menu podręcznym okna kodu źródłowego (wyświetlanym po kliknięciu prawym przyciskiem myszy linii kodu) możesz ustawiać, usuwać, włączać lub wyłączać punkty wstrzymania. Możesz
także wykonywać pojedynczą linię programu. W tym menu podręcznym możesz także przywołać okno disassemblera lub okno dialogowe QuickWatch, czyli szybkiego podglądu wartości zmiennych.
Okno zmiennych zawiera listę zmiennych zdefiniowanych wewnątrz bieżącej funkcji. To okno posiada trzy zakładki: Auto, Locals oraz this. Zakładka Auto wyświetla zmienne używane przez program w aktualnej i poprzedniej linii kodu. Zakładka Locals wyświetla zmienne zdefiniowane lokalnie wewnątrz bieżącej funkcji, łącznie z parametrami funkcji. Zakładka this, jak można oczekiwać, zawiera obiekt wskazywany aktualnie przez zmienną wskaźnik this. Okno zmiennych z wybraną zakładką Auto przedstawia rysunek 3.5.
Okna zmiennych możesz użyć także do przeglądania zmiennych w zakresie funkcji wywołujących aktualnie wykonywaną funkcję. Oprócz tego, w trakcie przechodzenia krokowo przez kod aktualnie wykonywanej funkcji, zmienne o zmienionej wartości są wyświetlane w innym kolorze.
Okna zmiennych możesz używać do zmiany wartości zmiennych typów prostych (takich jak int, double czy wskaźnik). Aby zmodyfikować wartość zmiennej, dwukrotnie kliknij wartość w oknie zmiennych. Jeśli debugger umożliwi zmianę wartości zmiennej, wewnątrz okienka pojawi się kursor tekstowy.
Podczas sesji debuggowania możesz skorzystać z okna podglądu zmiennych w celu sprawdzenia wartości innych zmiennych i wyrażeń. W polu Name w oknie podglądu możesz wpisać nazwę zmiennej lub wyrażenie lub wkleić je z okna kodu źródłowego. Okno podglądu zmiennych zostało przedstawione na rysunku 3.6.
Jak widać, okno podglądu zmiennych ma cztery zakładki. Podczas sesji debuggowania możesz użyć tych zakładek w celu wykorzystania czterech różnych zestawów śledzonych wyrażeń. Gdy Twój program stanie się bardziej skomplikowany i zaczniesz używać własnych klas i obiektów, możliwość przeglądania różnych zestawów zmiennych stanie się nieocenioną pomocą.
Podobnie do okna zmiennych okno podglądu zmiennych używa innego koloru w celu wyświetlenia wartości zmiennych, które uległy zmianie w wyniku wykonania instrukcji kodu. Oprócz tego, możesz dokonywać zmiany wartości zmiennych prostych typów, podobnie jak w oknie zmiennych, dwukrotnie klikając wybraną wartość.
Okno Registers (rejestry) zawiera aktualną zawartość rejestrów procesora, włącznie z rejestrami koprocesora arytmetycznego. (Jeśli zdecydujesz się na wyświetlanie ich zawartości). Tak jak w przypadku okna zmiennych oraz okna podglądu zmiennych, w oknie rejestrów zmienia się kolor rejestrów zmodyfikowanych w wyniku wykonania pojedynczego kroku programu. Okno rejestrów zostało przedstawione na rysunku 3.7.
Okno Memory (pamięć) umożliwia przeglądanie zawartości pamięci należącej do przestrzeni adresowej procesu (aplikacji, DLL-a lub innego programu), który debuggujesz. Okno zawartości pamięci może wyświetlać zawartość w postaci bajtów, słów lub podwójnych słów. Jeśli wybierzesz format bajtów, po prawej stronie okna zostaną wyświetlone także znaki ASCII odpowiadające kolejnym komórkom pamięci. Do wyboru formy wyświetlania zawartości pamięci możesz użyć menu podręcznego, rozwijanego po kliknięciu w oknie Memory prawym przyciskiem myszy. Rysunek 3.8 przedstawia okno zawartości pamięci zaczynającej się od położenia w pamięci zmiennej hinstance programu.
Aby wyświetlić zawartość pamięci w określonej lokalizacji, w polu Address w oknie Memory wpisz odpowiednie wyrażenie. Zwróć uwagę, że w oknie zawartości pamięci można wyświetlić zawartość pamięci poprzedzającej wskazany adres. Ponieważ okno może wyświetlać zawartość pamięci poprzedzającej i następującej, jeśli podasz adres symboliczny (na przykład nazwę zmiennej) możesz mieć problem z jej interpretacją. Na szczęście okno automatycznie umieszcza kursor tekstowy w miejscu pamięci odpowiadającym początkowi bloku reprezentowanego przez tą zmienną lub wyrażenie. Podobnie do innych okien debuggera, także w oknie zawartości pamięci wartości zmienione w wyniku pracy krokowej wyświetlane są w innym kolorze.
Okno stosu wywołań (Cali Stack) zawiera hierarchiczną listę wywołań funkcji, prowadzącą do funkcji aktualnie wykonywanej przez aplikację. Jeśli w oknie stosu wywołań dwukrotnie klikniesz nazwę funkcji, debugger zaktualizuje okno kodu źródłowego i inne okna debug-gowania, odzwierciedlając kontekst funkcji, którą wybrałeś. Wybranie funkcji w oknie Cali Stack (pojedynczym kliknięciem) i wciśnięcie klawisza F7 powoduje wykonanie kodu programu do momentu dojścia do wskazanej funkcji. Okno stosu wywołań zostało przedstawione na rysunku 3.9.
Podczas debuggowania programu możesz wykorzystać okno stosu wywołań jako efektywne narzędzie do wyznaczenia serii wywołań powodujących dany błąd.
Okno disassemblera (Disassembly) zawiera widok kodu asemblera wygenerowanego przez kompilator dla aplikacji. Gdy okno disassemblera jest aktywne (tzn. jest oknem wybranym), możesz użyć go do wykonywania programu krokowo według instrukcji procesora, a nie instrukcji języka C/C++. Wykonywanie krok po kroku instrukcji asemblera może pomóc w określeniu, która część wyrażenia powoduje błąd. Okno disassemblera zostało przedstawione na rysunku 3.10.
Dostęp do specjalnych funkcji okna disassemblera odbywa się poprzez menu podręczne, otwierane za każdym razem gdy klikniesz w oknie prawym przyciskiem myszy. Polecenie Set Next Statement (ustaw następną instrukcję) umożliwia zmianę wskaźnika programu w procesorze. Dzięki temu poleceniu możesz nakazać wykonanie dowolnej instrukcji, która jest wskazywana kursorem tekstowym. Możesz na przykład użyć tej możliwości do pominięcia fragmentu kodu. Powinieneś jednak korzystać z tego z zachowaniem maksymalnej uwagi, gdyż jeśli ustawisz kursor w ciele innej funkcji lub nie zmodyfikujesz odpowiednio stosu, wyniki będą trudne do przewidzenia i debuggowana aplikacja najprawdopodobniej się załamie.
Korzystanie z punktów wstrzymania i wykonywanie programu krok po kroku
Dwie podstawowe cechy każdego debuggera i jedne z najmocniejszych stron debuggera zintegrowanego z Visual Studio to możliwość wstawiania w kod programu punktów wstrzymania oraz możliwość wykonywania kodu programu krok po kroku (po jednej instrukcji naraz).
Najprostszym sposobem umieszczenia punktu wstrzylnania wewnątrz kodu jest umieszczenie kursora tekstowego w danej linii w oknie edytora kodu i wciśnięcie klawisza F9. W celu wskazania istnienia punktu wstrzymania Yisual Studio umieści na lewym marginesie okna dużą czerwoną kropkę. Wygląd okna edytora kodu z dwoma punktami wstrzymania przedstawia rysunek 3.11.
Zanim przejdziemy do bardziej skomplikowanych punktów przerwań, powinieneś poznać dwie rzeczy dotyczące prostszych punktów. Po pierwsze, punkty wstrzymania mogą być umieszczane w dowolnej części pliku źródłowego - w linii komentarza, na nawiasie klamrowym itd. Jednak podczas kompilowania programu, Visual C++ przeniesie te punkty do następnej linii kodu, która faktycznie może zostać wykonana. Po drugie, Visual Studio umożliwia umieszczanie punktów wstrzymania także w oknie disassemblera.
Dużo bardziej precyzyjne sterownie punktami wstrzymania odbywa się poprzez polecenie Breakpoints w menu Edit. Gdy wybierzesz polecenie Breakpoints, Visual Studio wyświetli okno dialogowe o tej samej nazwie, w którym możesz ustawić trzy różne rodzaje punktów wstrzymania.
Punkty wstrzymania typu location (położenie) powodują wstrzymanie działania programu po dojściu do określonego miejsca kodu. Punktami wstrzymania tego typu są właśnie punkty wstawiane przez wciśnięcie klawisza F9 w oknie kodu źródłowego. Do punktu wstrzymania tego rodzaju możesz zastosować także sprawdzanie określonego warunku. Jeśli dodasz sprawdzanie warunku, punkt wstrzymania spowoduje zatrzymanie działania programu tylko wtedy, gdy zadany warunek będzie spełniony.
Punkty wstrzymania typu data (dane) powodują wstrzymanie działania programu w momencie gdy zmienia się wartość określonego wyrażenia. W przypadku punktów wstrzymania położenia i danych możesz kliknąć na trójkątnym przycisku obok identyfikatora punktu wstrzymania w celu przywołania okna dialogowego zaawansowanych punktów wstrzymań (Advanced Breakpoint). W tym oknie możesz określić kontekst punktu wstrzymania, łącznie z funkcją, do której punkt wstrzymania się odnosi, zawierającym go plikiem źródłowym oraz plikiem wykonywalnym, w którym punkt ma zostać umieszczony. Okno dialogowe Advanced Breakpoint zostało przedstawione na rysunku 3.12.
Trzeci typ punktu wstrzymania to tzw. message breakpoint (punkt wstrzymania komunikatu). Punkt wstrzymania tego typu powoduje zatrzymanie działania programu w momencie, gdy jedna z procedur okien w Twoim programie otrzyma określony komunikat. (Okna cały czas otrzymują komunikaty od systemu operacyjnego - na przykład wtedy, gdy użytkownik wciśnie klawisz). Ustawienie punktu wstrzymania komunikatu umożliwia zatrzymanie programu w momencie wystąpienia określonej akcji (na przykład upuszczenia w oknie obiektu OLE lub wciśnięcia przez użytkownika kombinacji klawiszy, na przykład Alt+FlO) i zapewnia, że dane okno poprawnie przetworzy tę akcję. Rysunek 3.13 przedstawia okno dialogowe Breakpoints w momencie ustawiania punktu wstrzymania komunikatu.
Punkt wstrzymania może być włączony lub wyłączony. Gdy punkt wstrzymania jest włączony i aplikacja jest wykonywana w trybie debuggowania, w oknie dialogowym Breakpoints, obok punktu wstrzymania, wyświetlana jest zaznaczona opcja. Gdy wyłączysz opcję obok punktu wstrzymania, punkt zostanie wyłączony (stanie się nieaktywny). Visual Studio wyświetla nieaktywne punkty wstrzymania jako okrągłe czerwone kółka z pustym środkiem.
Oprócz korzystania z punktów wstrzymania działanie programu możesz przerwać w dowolnym momencie za pomocą polecenia Break (przerwij) w menu Debug. Jednak takie wstrzymanie jest z natury asynchroniczne i zwykle powoduje zatrzymanie działania programu głęboko w serii zagnieżdżonych wywołań funkcji systemowych. W takich przypadkach możesz użyć polecenia Step Out (wyjdź z) w menu Debug w celu opuszczenia funkcji systemowych i powrotu do znanego Ci miejsca w Twoim programie.
Polecenie Step Out w menu Debug jest jednym z kilku poleceń pracy krokowej, których możesz użyć do wykonania pojedynczych instrukcji programu. Najprostszym poleceniem pracy krokowej jest polecenie Step In (wejdź do), powodujące wykonanie następnej linii kodu źródłowego lub następnej instrukcji w oknie disassemblera (w zależności od tego, które z tych okien jest aktywne). Jeśli następna linia w programie lub instrukcja asemblera jest wywołaniem funkcji (lub instrukcją cALL), po wybraniu polecenia Step In program przechodzi do ciała wywoływanej funkcji.
Polecenie Step Over (przejdź przez) jest podobne do polecenia Step In, z tym że nie powoduje przejścia do ciała wywoływanej funkcji. Zamiast tego wykonanie programu obejmuje całą wywoływaną funkcję (i funkcje wywoływane w niej) i jest zatrzymywane dopiero po powrocie z tej funkcji, na następnej instrukcji po wywołaniu.
Polecenie Run to Cursor (wykonaj do kursora), ogólnie rzecz biorąc, polega na umieszczeniu w miejscu kursora tekstowego Jednorazowego" punktu wstrzymania i wykonanie programu aż do tego punktu lub do innego napotkanego po drodze punktu wstrzymania.
Polecenia Step Into Specific Function (wejdź do określonej funkcji) możesz użyć w przypadku, gdy chcesz precyzyjnie określić, do której funkcji chcesz przejść, gdy pojedyncza linia kodu źródłowego zawiera kilka zagnieżdżonych wywołań funkcji. Jeśli wskaźnik wykonania programu nie znajduje się w linii zawierającej zagnieżdżone wywołania funkcji, Visual Studio wyłącza to polecenie menu.
Wiele z poleceń pracy krokowej posiada własne skróty klawiatury. Jak się przekonasz, krokowe wykonywanie programu jest dużo łatwiejsze, gdy korzysta się ze skrótów klawiatury a nie z poleceń menu wybieranych myszką. Tabela 3.1 zawiera skróty klawiatury dla poleceń pracy krokowej w menu Debug.
Gdy program jest zatrzymany w debuggerze, możesz określić instrukcję, od której będzie kontynuowane wykonywanie programu. W tym celu w oknie kodu źródłowego lub w oknie disassemblera powinieneś użyć polecenia Set Next Statement (ustaw nową instrukcję). Jak już wiesz, korzystając z tego polecenia, powinieneś zachować wzmożoną ostrożność -wznowienie działania w innej funkcji lub w sposób powodujący naruszenie stosu może doprowadzić do poważnych konsekwencji.
Tabela 3.1. Skróty klawiatury dla poleceń pracy krokowej
Polecenie
Kombinacja klawiszy skrótu
Step Over (przejdź przez)-F10
Run to Cursor (wykonaj do kursora)-Ctrl+Fl0
Step Into (wejdź do)-F11
Step Out (wyjdź z)- Shift+F11
Korzystanie z etykietek danych i okna szybkiego podglÄ…du
Mimo całej potęgi oferowanej przez okna debuggowania, czasem może zdarzyć się, że będziesz potrzebował informacji, których nie ma ani w oknie podglądu zmiennych, ani w oknie zmiennych. Zintegrowany z Visual C++ debugger udostępnia więc dwa dodatkowe narzędzia, których możesz w tym celu użyć: informacji DataTips (etykietek danych) oraz okna QuickWatch (szybkiego podglądu).
Etykietki danych są podobne do z pewnością znanych Ci etykietek przycisków, pojawiających się gdy kursor myszy na chwilę spocznie nieruchomo na przycisku paska narzędzi. Jeśli podczas sesji debuggera umieścisz wskaźnik myszy na nazwie symbolu, który może zostać obliczony, Visual Studio wyświetli etykietkę zawierającą wartość tego symbolu. Taka etykietka jest widoczna na rysunku 3.14.
Przeznaczenie i wygląd okna szybkiego podglądu są podobne do przeznaczenia i wyglądu okna podglądu zmiennych. Także w oknie szybkiego podglądu możesz zmieniać wartości zmiennych prostych typów, jednak jak już wspomnieliśmy, możesz także umieszczać w tym oknie specyficzne symbole. Okno szybkiego podglądu zostało przedstawione na rysunku 3.15.
Użycie okien wątków i wyjątków w trakcie debuggowania
Jak zapewne wiesz, 32-bitowe środowisko programowe Windows jest środowiskiem wielowątkowym. Debuggowanie wielowątkowych aplikacji powoduje powstanie dodatkowych komplikacji, które jeszcze bardziej utrudniają analizę działania programów. Debugger w Visual Studio posiada okno dialogowe Threads (wątki), którego możesz użyć podczas debuggowania do wybrania wątku w wielowątkowej aplikacji, który chcesz poddać analizie. Do przywołania tego okna dialogowego służy polecenie Threads w menu Debug, zaś samo okno zostało pokazane na rysunku 3.16.
Oprócz okna dialogowego Threads Visual C++ oferuje także okno dialogowe Exceptions (wyjątki). Możesz w nim precyzyjnie określić sposób, w jaki Twój program będzie odpowiadał na wyjątki, które wystąpią w trakcie sesji debuggowania. Możesz wybrać wyjątki standardowe lub wyjątki definiowane przez użytkownika. Wewnątrz okna dialogowego wskaż działanie, które debugger powinien podjąć w momencie, gdy program powiadomi go o określonym wyjątku. Domyślnie, debugger w przypadku nieobsłużenia któregoś z większości wyjątków powoduje zatrzymanie działania programu (opcja Stop if not handled). Okno dialogowe wyjątków zostało pokazane na rysunku 3.17.
Proste techniki debuggowania
Debugger zintegrowany z Yisual C++ oraz różne funkcje wbudowane przez Microsoft w bibliotekę MFC umożliwiają korzystanie z różnorodnych technik debuggowania. W następnych sekcjach zajmiemy się najczęściej stosowanymi technikami debuggowania, których możesz użyć podczas analizy swoich programów.
Korzystanie z okien komunikatów w celu przyspieszenia debuggowania
Choć wbudowany debugger oferuje wiele funkcji i ułatwień, czasem podczas analizowania działania programu nie jest wygodnie z niego korzystać. Na przykład, obecność okna debuggera może wpływać na działanie programu lub na przykład błąd objawia się wyłącznie w ostatecznej wersji programu. W takich przypadkach do wyeliminowania błędu może wystarczyć zwykłe okno komunikatu. Na przykład, jeśli odkryjesz błędne działanie dwuparametrowej funkcji ErrFunc, możesz łatwo sprawdzić, czy otrzymuje ona poprawne parametry, dodając wywołanie AfxMessageBox (), tak jak pokazano w poniższym kodzie:
char temparr[100];
wsprintf(temparr, "Wywołanie ErrFunc(x = %d,y = %d)", x, y)
AfxMessageBox(temparr);
ErrFunc(x, y);
Okno komunikatu wyświetli napis jeszcze przed wywołaniem funkcji ErrFunc - co może dać Ci szansę przerwania wykonania programu, zmiany wartości x i y lub po prostu sprawdzenia, czy błąd występuje w obrębie funkcji, a nie z powodu błędnych parametrów.
Wyjście debuggera
Jednym z elementów wbudowanych przez Microsoft w bibliotekę MFC jest to, że większość funkcji MFC automatycznie generuje informacje wyjściowe debuggera. Ty również w kodzie swojego programu możesz użyć makr TRACĘ, TRACEO, TRACĘ l, TRACE2 lub TRACE3 do wygenerowania danych wyjściowych debuggera. Debugger wysyła informacje wyjściowe do obiektu afxDump, standardowo zdefiniowanego obiektu klasy MFC CDumpContext. Yisual Studio zwykle przekazuje wyjście obiektu afxDump do okna Output (wyjście). Aby zobaczyć jego zawartość, w oknie debuggera kliknij zakładkę Debug. Na przykład, aby sprawdzić wartości przekazywane przez program do funkcji ErrFunc (), mógłbyś napisać kod podobny do poniższego:
TRACE2("Wywołanie ErrFunc(x = %d, y = %d)", x, y);
ErrFunc(x, y);
Wynik działania makra TRACE2 ujrzysz tylko wtedy, gdy skompilujesz swoją aplikację dla debuggowania. Oprócz tego, musisz uruchomić aplikację w debuggerze, nawet jeśli nie chcesz korzystać z żadnych innych oferowanych przez niego możliwości.
Ogólnie rzecz biorąc, jeśli to możliwe, powinieneś używać makr TRACEO, TRACĘ l, TRACE2 i TRACE3, gdyż każde z nich wykorzystuje mniej pamięci niż makro TRACE. Makro TRACEO wymaga podania jedynie łańcucha formatującego i może być użyte do wyświetlenia prostych napisów informacyjnych zrzucanych przez aplikację do obiektu afxDump. Makro TRACE l przetwarza łańcuch formatujący i jeden argument (jedną zmienną zrzucaną do afxDump). Makro TRACE2 przetwarza łańcuch formatujący i dwa argumenty (dwie zmienne zrzucane do afxDump). Makro TRACE2, jak się domyślasz, przetwarza łańcuch formatujący i trzy argumenty (trzy zmienne zrzucane do afxDump). Makra TRACEn możesz użyć wtedy, gdy wiesz, ile zmiennych ma zostać zrzuconych. Oprócz tego, makra TRACE/] są użyteczne w konfiguracjach Unicode, gdyż w makrze TRACE musisz korzystać z przedrostka łańcucha _r, zaś w makrach TRACEn nie ma takiej konieczności.
Co więcej, nie możesz użyć żadnego z makr z rodziny TRACĘ, jeśli nie zbudujesz programu dla debuggowania - wersje ostateczne (release) całkowicie ignorują makra TRACE.
Korzystanie z asercji
Jednym z najczęściej wykorzystywanych i najbardziej wydajnych narzędzi w arsenale debuggera jest makro ASSERT. Możesz użyć tego makra przerwania działania programu w momencie, gdy określony warunek przybierze wartość FALSE. Makra ASSERT możesz użyć w aplikacjach skonfigurowanych dla debuggera na przykład w celu weryfikacji, czy funkcja otrzymuje właściwe parametry. Wciąż korzystając z przykładu ErrFunc (), możesz umieścić makro ASSERT na samym początku funkcji, na przykład tak:
void ErrFunc(int x, int y) {
ASSERT (x >= O && y < 100);
Makra ASSERT_VALID możesz użyć zawsze wtedy, gdy chcesz sprawdzić, czy wskaźnik wskazuje poprawny obiekt klasy wyprowadzonej z klasy cobject. Na przykład, gdy w swojej funkcji korzystasz z funkcji GetDocument (), która zwraca wskaźnik do obiektu typu csampleDoc, możesz sprawdzić poprawność zwracanego wskaźnika za pomocą makra ASSERT_VALID. Możesz użyć kodu podobnego do poniższego:
CSampleDoc *pDoc; pDoc = GetDocument O; ASSERT_VALID(pDoc);
Zarówno ASSERT jak i ASSERT_VALID wyświetla okno komunikatu zawierające numer linii programu, w którym wystąpiła asercja. Debugger przerywa działanie programu, pozostawiając wskaźnik programu w linii zawierającej makro. Podobnie do makra TRACE, makra ASSERT nie mają żadnego efektu, jeśli aplikacja nie zostanie zbudowana w konfiguracji dla debuggowania.
Zrzut obiektów
Klasa cobject posiada funkcję składową DumpO, służącą do zrzucenia zawartości obiektu do okna wyjścia debuggera (poprzez obiekt afxDump). Jeśli masz zamiar zrzucać zawartości obiektów wyprowadzonych z klasy cobject, powinieneś w tych klasach zaimplementować funkcję składową DumpO. Na przykład, jeśli wyprowadzisz własną klasę csampleDoc dokumentu z klasy MFC CDocument i ta klasa będzie zawierać dwie składowe, m_xPox oraz m_yPos, Twoja implementacja funkcji csampleDoc: : Dump () może wyglądać mniej więcej tak:
#ifdef _DEBUG // sprawdzenie czy to jest konfiguracja dla debuggera
void CSampleDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
dc « "m_xPos = " m_xPos « endl;
dc « "m_yPos = " m_yPos « endl; }
#endif // DEBUG
Klasa CMemoryState i wykrywanie wycieków pamięci
Klasy CMemoryState możesz użyć w celu wykrycia wycieków pamięci wynikających z niewłaściwego użycia operatorów C++ new lub delete, alokujących i zwalniających pamięć aplikacji. Aby w dowolnym momencie utworzyć migawkę obrazującą wykorzystanie pamięci przez aplikację, możesz utworzyć obiekt CMemoryState i wywołać jego funkcję składową Checkpoint (). Później możesz wywołać funkcję składową DumpAllobjectsSince o w celu zrzucenia zawartości wszystkich obiektów zaalokowa-nych przez program od czasu ostatniego wywołania funkcji składowej Checkpoint (). Na przykład, aby zrzucić wszystkie obiekty, które funkcja sioppyFunc() zaalokowała i "zapomniała" usunąć, powinieneś użyć kodu podobnego do poniższego:
CMemoryState memState; memState.Checkpoint(); SloppyFunc(x, y); memState.DumpAllobjectsSince();
Jeśli nie potrzebujesz kompletnego zrzutu obiektów zaalokowanych od czasu wywołania Checkpoint (), możesz użyć funkcji składowej Dumpstatistics (). Możesz użyć tej funkcji gdy program, w wyniku wywołania funkcji składowej Dif f erence (), wykryje różnice pomiędzy dwoma stanami pamięci. Aby użyć funkcji Dumpstatistics (), musisz łącznie stworzyć trzy obiekty klasy CMemoryState. Pierwsze dwa z nich zostaną użyte do utworzenia migawek obrazujących stany pamięci, zaś trzeci będzie zawierał różnice pomiędzy tymi stanami. W celu sprawdzenia stanu pamięci możesz użyć kodu podobnego do poniższego:
CMemoryState msBeforeCall, msAfterCall, msDiffBA; // tutaj pozostały kod msBeforeCall.Checkpoint(); SloppyFunc(x, y); msAfterCall.Checkpoint();
if{ msDiffBA.Difference(msBeforeCall, msAfterCall)) msDiffBA.DumpStatistics();
Nie możesz używać obiektów CMemoryState w celu wykrycia wycieków pamięci wynikających z niewłaściwego użycia w programie funkcji malloc/free, GlobalAiioc/Global-
Free lub LocalAlloc/LocallFree.
Komunikaty śledzenia MFC
Jak dowiedziałeś się we wcześniejszej części rozdziału, wersja debug biblioteki MFC wysyła wiele komunikatów śledzenia do zakładki Debug w oknie danych wyjściowych Yisual Studia. Do włączenia lub wyłączenia części lub wszystkich komunikatów śledzenia MFC możesz użyć aplikacji MFCTracer programu tracer.exe. Do przywołania tej aplikacji możesz użyć polecenia MFC Tracer w menu Tools. Aplikacja wyświetla proste okno dialogowe, w którym możesz włączyć lub wyłączyć generowanie wybranych komunikatów śledzenia. Na rysunku 3.18 przedstawiono okno dialogowe programu, MFC Tracę Options, w którym możesz włączać lub wyłączać komunikaty.
Zdalne debuggowanie
Często może zdarzyć się, że będziesz debuggował programy lub pomagał w debuggowaniu programów działających w komputerze innego użytkownika. Zdalne debuggowanie (ang. remote debugging) umożliwia debuggowanie kodu programu działającego w innym komputerze, do którego jest podłączony Twój komputer. Lokalny i zdalny komputer muszą być podłączone kablem szeregowym lub poprzez lokalną sieć komputerową. W lokalnym komputerze musi działać Visual C++ oraz zintegrowany debugger, podczas gdy w komputerze zdalnym musi działać jedynie debuggowana aplikacja oraz monitor debug-gowania (Visual C++ Debug Monitor). Proces komunikacji pomiędzy zdalnym a lokalnym komputerem w trakcie sesji debuggowania ilustruje rysunek 3.19.
Jak wspomniałem przed chwilą, aby zdalny komputer mógł obsłużyć zdalne debuggowania, musi w nim działać aplikacja Yisual C++ Debug Monitor, Msvcmon.exe. Aby ta aplikacja poprawnie działała, w zdalnym komputerze musisz zainstalować także następujące biblioteki DLL: Msvcrt.dll, TlnOt.dll, Dm.dll, Msvcp60.dll oraz Msdis100.dll Wszystkie te pliki musisz skopiować do kartoteki wymienionej w systemowej ścieżce dostępu - najlepiej do kartoteki systemowej Windows.
Visual Studio automatycznie instaluje te pliki w każdym komputerze, w którym instalujesz pakiet Visual Studio. Domyślna instalacja umieszcza program Msvcmon.exe w podkartotece Common\MSDev98\Bin w kartotece Visual Studia.
Rys. 3.19.
Ścieżka komunikacji
pomiędzy komputerem
lokalnym,
komputerem
zdalnym ora: zdalnie
debuggowanÄ…
aplikacjÄ…
Zdalny komputer
DebuggowanÄ… aplikacja
Visual C++ Debug Monitor
Sieciowy protokół transportowy
Lokalny komputer
Zintegrowany debugger
Visual Studio
Sieciowy protokół transportowy
Aby użyć zdalnego debuggowania, przed uruchomieniem samej aplikacji, w zdalnym komputerze musisz uruchomić monitor debuggowania (Msvcmon.exe}. Po uruchomieniu zostanie wyświetlone okno dialogowe, w którym musisz określić ustawienia programu. Najczęściej zdalne debuggowanie odbywa się poprzez połączenie sieci TCP/IP. Po wybraniu połączenia możesz kliknąć przycisk Settings (ustawienia) w celu określenia szczegółów tego połączenia - nazwy komputera docelowego lub adresu oraz hasła dostępu, jeśli takowe obowiązuje. Okno dialogowe monitora debuggowania obrazuje rysunek 3.20.
Po wybraniu docelowego komputera kliknij przycisk Connect (połącz). Monitor debuggowania rozpocznie oczekiwanie na połączenie. Aby skonfigurować lokalny komputer, tak aby odpowiedział na żądanie połączenia, musisz w nim najpierw uruchomić Visual Studio.
Po uruchomieniu Visual Studia w menu Build wybierz polecenie Debugger Remote Connec-tion (zdalne połączenie debuggera). Visual Studio wyświetli okno dialogowe Remote Connection. W tym oknie powinieneś określić rodzaj połączenia (w naszym przykładzie Network TCP/IP), a następnie, po kliknięciu przycisku Settings (ustawienia), określić jego parametry. Okno dialogowe Remote Connection zostało przedstawione na rysunku 3.21.
Gdy ustawiasz połączenie sieciowe, zarówno monitor debuggowania jak i zdalne połączenie proszą o podanie hasła dla połączenia. Upewnij się, że oba hasła są takie same, gdyż w przeciwnym razie nie będziesz mógł nawiązać komunikacji.
Główną zaletą zdalnego debuggowania jest to, że aplikacja działa w komputerze, na który nie ma wpływu obecność debuggera. Zdalne debuggowanie jest więc idealne dla aplikacji przejmujących kontrolę nad ekranem Windows, klawiaturą, sterownikami dźwięku itd. - na przykład pełń oe kranowy m i grami. Zdalne debuggowanie przydaje się także w przypadku aplikacji działających poprawnie po zbudowaniu ich w wersji dla debuggowania, lecz załamujących się po skompilowaniu ich w wersji ostatecznej (release).
Debuggowanie "just-in-time"
Debuggowanie ,just-in-time" reprezentuje zdolność debuggera Yisual C++ do podłączania się do działającego programu, który uległ zatrzymaniu z powodu nie obsłużonego wyjątku. Takie debuggowanie jest przydatne do analizowania działania aplikacji, które nie zostały uruchomione w zintegrowanym debuggerze lub które nie zostały zbudowane z dołączonymi informacjami dla debuggowania.
Debuggowanie ,just-in-time" możesz włączyć, wykorzystując polecenie Options w menu Tools pakietu Visual Studio. W oknie dialogowym Options kliknij zakładkę Debug, po czym włącz opcję Just-in-time debugging.
Po zainstalowaniu Visual Studia w komputerze debuggowanie Just-in-time" jest włączone domyślnie.
Debuggowanie typu "edit and continue"
W miarę wzrostu popularności narzędzi takich jak RAD (Rapid Application Deve-lopment) Yisual Basica, wiele z ich charakterystyk zostaje przejętych przez interfejs użytkownika pakietu Visual Studia (obecnie Microsoft próbuje nawet stworzyć pojedynczy, zunifikowany interfejs dla Visual Basica, Visual C++, Visual FoxPro, Yisual J++ i pewnych programów wspomagających). Jedną z powszechnie wykorzystywanych możliwości kompilatora Visual Basica jest mechanizm "edit and continue", umożliwiający dokonywania zmian w kodzie aplikacji już w trakcie jej wykonywania i wykorzystywania tych zmian do usuwania jej błędów.
W Visual C++ 6.0 możesz obecnie korzystać z tego mechanizmu w aplikacjach zbudowanych w konfiguracji do debuggowania. Jednak w odróżnieniu od Visual Basica debugger Visual C++ posiada jedno poważne ograniczenie swojego użycia z programami. Gdy użyjesz opcji "edit and continue" debuggera, musisz upewnić się, czy zastąpiłeś dokładnie tyle samo bajtów kodu, ile występowało w oryginalnej wersji aplikacji. Na przykład, możesz zastąpić liczbę inną liczbą - nie możesz jednak zastąpić stałej znakowej (na przykład 'A') łańcuchem znaków (na przykład "A"), gdyż taki łańcuch jest o jeden bajt dłuższy (z powodu bajtu O kończącego łańcuch). Jeśli dokonasz zmiany nie obsługiwanej bezpośrednio przez mechanizm "edit and continue", Yisual Studio ostrzeże Cię o tym i zaproponuje ponowne skompilowanie projektu lub anulowanie zmiany.
Debuggowanie "edit and continue" w Visual Studio działa tylko wtedy, gdy kompilator poprawnie skompiluje aplikację - co oznacza, że możesz go użyć wyłącznie do usuwania błędów logicznych, a nie błędów składniowych. Kompilator wychwytuje błędy składniowe, zanim jeszcze przystąpisz do debuggowania.
Debuggowanie usług Windows NT
Jak już wiesz, zintegrowany debugger umożliwia analizę działania każdej aplikacji, którą możesz stworzyć za pomocą Visual Studia - nie tylko standardowych aplikacji wykonywalnych. Doskonałym przykładem aplikacji innego typu, które mogą być analizowane po załamaniu, są usługi Windows NT.
Najprostszym sposobem rozpoczęcia debuggowania usługi serwera Windows NT jest sztuczne uruchomienie jej jako aplikacji konsoli - innymi słowy, uruchomienie jej w linii poleceń. Uczynienie tego umożliwia przejście przez kod usługi począwszy od pierwszej instrukcji, pełny dostęp do zintegrowanego debuggera Visual Studia oraz korzystanie z okna wyświetlającego komunikaty MAPI.
Aby skonfigurować usługę jako aplikację konsoli, musisz obsłużyć kody zwracane przez menedżera usług Windows NT, a następnie we własnym kodzie startowym podjąć odpowiednią ścieżkę dla kodu. Innymi słowy, gdy aplikacja działa jako usługa serwera Windows NT, system operacyjny zwykle wywołuje menedżera usług w celu znalezienia głównej funkcji aplikacji. Jeśli proces sztucznie działa jako aplikacja konsoli, wywołanie menedżera usług nie powiedzie się. W tej sytuacji powinieneś w debuggerze jawnie wywołać swoją główną funkcję.
Aby uruchomić usługę jako aplikację konsoli, musisz do pliku makefile projektu (lub jako zewnętrzną zależność) dołączyć bibliotekę Winwrap.lib. W ten sposób obsłużysz wywołania menedżera usług. Jeśli nie chcesz dołączać tej biblioteki, przejrzyj jej kod źródłowy i dokonaj odpowiednich zmian w głównej funkcji swojej usługi.
Podsumowanie
W tym rozdziale poznałeś zintegrowany debugger Visual C++ oraz korzyści, które płyną z używania go przy debuggowaniu i analizowaniu swoich programów. Okno debuggera dostarcza w większości przypadków nawet większej ilości informacji niż mógłbyś sobie życzyć. Makra ASSERT, punkty wstrzymań, etykietki danych i inne elementy wciąż dostarczaj ą aktualnych informacji na temat bieżącego stanu aplikacji.
Jednak nawet najlepszy debugger nie zastąpi dobrego, solidnego programowania. Im lepszy kod napiszesz na początku, tym mniej czasu spędzisz z debuggerem i tym mniej czasu poświęci na analizę programu ktoś inny, kto będzie musiał go rozbudować lub zmodyfikować. Zintegrowany debugger pomaga w usunięciu wielu błędów logicznych - powinieneś jednak dokonać wszelkich starań, aby wyciągnąć wnioski z tych błędów, tak aby nie powtarzać ich w przyszłości.
Wyszukiwarka
Podobne podstrony:
Co dalej z leczeniem cukrzycy, gdy leki doustne nie działająopel corsa C nie dzialaja swiatla postojowemb W124 nie dziala radioOpel Astra G nie dziala klimatyzacja1MB W210 klimatyzacyjna czasowo nie dzialaJak sprzedawac gdy nikt nie kupuje I jak sprzedawac wiecej kiedy juz zacznabmw E39 E53 nie dziala dmuchawaOpel Astra F Omega B nie dziala dmuchawagdy sie nie ma 4więcej podobnych podstron