Software-Ontwikkeling I Academiejaar 2006 - 2007
Practicum 1 Inleiding tot Microsoft Visual C++ en programmeren in C/C++ onder Linux
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
1
Inleiding tot de practica Dit inleidend practicum heeft tot doel U vertrouwd te maken met Microsoft Visual C++ 2005 Express Edition, de ontwikkelomgeving die doorheen de practica zal gebruikt worden. Tijdens dit practicum zal er ook dieper worden ingegaan op de ontwikkeling van C/C++ applicaties onder Linux. Tot slot volgt er een eenvoudige programmeer-oefening. Zit je met vragen over de practica, neem dan gerust contact op met de assistenten tijdens één van de lessen of door te mailen naar
[email protected].
Microsoft Visual C++ Inleiding Tijdens deze practica zullen we gebruik maken van de Microsoft Visual C++ 2005 Express Edition. Deze editie is een gratis IDE en Visual C++ compiler die deel uitmaakt van de Express familie. Zoals bij alle andere Express applicaties, is het aantal beschikbare “features”, t.o.v. Microsoft Visual Studio, eerder beperkt. De Visual C++ 2005 Express Edition kan na installatie onmiddellijk worden gebruikt voor het compileren van .NET applicaties en Win32 console applicaties 1 . Code die geschreven wordt voor het .NET raamwerk noemt men ook wel managed code. Een voordeel van dergelijke code is dat de managed development environment de programmeur beschermt tegen vaak voorkomende Win32-fouten, zoals bijvoorbeeld het optreden van geheugenlekken. Unmanaged code heeft dan weer het voordeel dat het een hogere performantie levert. Zowel in de theorielessen als tijdens de practica zal de focus enkel liggen op unmanaged Win32 console applicaties. Win32 duidt op de 32-bits versie van de Windows API. Visual Studio, en de ervan afgeleide Express Editions, maken gebruik van Projects en Solutions voor het beheren van al je werk. Een Solution bevat één of meerdere projecten die meestal iets gemeenschappelijks hebben. De instellingen van een Solution worden opgeslagen in een bestand met de extensie .sln. Een Solution is vergelijkbaar met een workspace, wat gebruikt wordt in Eclipse en in oudere Microsoft IDEs. De 2005 editie biedt trouwens nog de mogelijkheid om deze oude Microsoft workspace bestanden (*.dsw) te openen. Een Project kan gezien worden als een applicatie en bevat de broncode van deze applicatie.
1
Met de Express Edition kan men standaard geen Win32 Windows applicaties ontwikkelen. Hiervoor moet je eerst de Platform SDK installeren en vervolgens Visual C++ 2005 E.E. herconfigureren. Dit valt echter buiten de scope van deze practica. Op http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/ vind je hierover meer info.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
2
De grafische omgeving Om vertrouwd te geraken met de IDE gaan we een nieuw project aanmaken en daar vervolgens bestaande code aan toevoegen.
Microsoft Visual C++ 2005 E.E. kan je opstarten via Athena en vind je terug onder de folder “\Academic\Development”. Je vindt in deze folder ook dev-c++ terug, d.i. een andere gratis ontwikkelomgeving voor C/C++ applicaties.
Maak binnen je eduserv-workspace 2 een nieuw project aan (zie Figuur1). Kies File – New – Project en selecteer als Project Type Win32. (CLR duidt op de managed .NET applicaties). Als Template selecteer je Win32 Console Application. Onderaan vul je dan een projectnaam, een opslaglocatie en de naam van de (nieuwe) Solution in.
Figuur 1: Aanmaken van een nieuw project.
2
Het is aan te raden om te werken via Eduserv omdat een lokaal project compileren met de Athena-versie van Visual C++ problemen kan geven (van de aard: Command line error D8003 : missing source filename.)
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
3
Na bevestigen wordt een Win32 Application wizard opgestart. Druk op Next, check of Console Application als Application type wordt weergegeven en vink Empty Project aan. Vervolgens kan je deze wizard beëindigen. Er is nu een nieuw project en een nieuwe Solution aangemaakt. Beide containers en hun hiërarchie vind je ook onmiddellijk terug in de Solution Explorer. Er worden automatisch ook 3 lege folders binnen het project aangemaakt. Naast de folder ‘Source files’, de folder voor de bronbestanden, is er een folder ‘Resource files’ voor extra data zoals bijvoorbeeld afbeeldingen en een folder ‘Header files’ voor de Header-bestanden, waarover later meer. Dit zijn echter virtuele folders, je zal ze niet terugvinden in de directorystructuur onder je project!
We gaan nu bestaande code toevoegen aan het project. Bij de projectopgave vind je het bestand ggd.c. Dit bevat de broncode van een kleine Win32 console applicatie die eerst 2 positieve gehele getallen opvraagt om er vervolgens de grootste gemene deler (GGD) van te berekenen. De extensie “.c” duidt op C-broncode, C++-bestanden krijgen “.cpp” als extensie!
Plaats het bestand ggd.c in je projectfolder! Vervolgens kan je dit C-bestand toevoegen aan de folder ‘Source files’ via rechtermuisknop (RMK) op deze doelfolder en vervolgens Add – Existing Item… .
Omdat het hier gaat om een C-bestand willen we er uiteraard zeker van zijn dat het ook als C-bestand, en niet als C++-bestand, wordt gecompileerd. Normaal zal de IDE op basis van de extensie hiermee rekening houden (ondanks het misleidende C++-logo dat steeds naast elk bronbestand wordt geplaatst).
Hoe een bronbestand dient te worden gecompileerd kan je ook zelf instellen via RMK op het bestand en vervolgens Properties – Configuration Properties – C/C++ Advanced – Compile As…. Ga na of het ingevoerde bestand als C-bestand wordt gecompileerd. Je kan dit op analoge wijze ook voor een geheel project instellen (zie Figuur 2). Standaard staat dit steeds ingesteld op ‘Compile as C++ code’, wijzig dit naar ‘Compile as C code’.
We kunnen nu het project gaan ‘builden’ (compileren + linken) via RMK op het project en dan te kiezen voor de actie ‘build’ (of via F7 bouw je alle projecten van de huidige Solution). Na het builden krijg je, als alles goed is verlopen, in het outputvenster de mededeling dat het proces is geslaagd (De 2 waarschuwingen die je krijgt betreffende scanf mag je voorlopig verwaarlozen). Je kan ook elk bestand apart compileren.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
4
Figuur 2: Wijzigen van de Project properties.
Je kan het project uitvoeren via Ctrl+F5 of via DebugÆStart Without Debugging. Via deze methode blijft de console zichtbaar na afloop van het programma tot de gebruiker een extra toets indrukt om de console af te sluiten.
Na het ingeven van 2 positieve gehele getallen krijg je als resultaat de grootste gemene deler van de 2 getallen terug. Door vervolgens op een willekeurige toets te drukken wordt de console gesloten. Je hoeft niet steeds eerst te ‘builden’ alvorens het programma uit te voeren. De IDE houdt bij of er sinds de laatste uitvoering bestanden zijn veranderd, en zal afhankelijk daarvan bestanden al dan niet opnieuw compileren en/of linken.
Opmerking: Via scanf kan men een hele reeks tekens tegelijkertijd inlezen. De betekenis van de syntaxis van de parameters wordt later in theorielessen uitgelegd.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
5
De debugger Via de debugger kan men de uitvoering van een programma stap voor stap doorlopen, wat vaak heel handig is tijdens het ontwikkelen van een programma. Men maakt hierbij gebruik van zogenaamde breakpoints. Via deze punten kan je aangeven waar de debugger precies dient te stoppen. Plaats je geen breakpoints dan zal het programma zonder pauzeren worden uitgevoerd, maar de console zal na het beëindigen van het programma deze keer onmiddellijk verdwijnen.
Zet een breakpoint aan de regel ‘printf("\nGetal 2: ");’. Dit doe je door in de grijze balk voor de coderegel te klikken, waardoor er een rode bol verschijnt. Vervolgens kan je een nieuwe debugsessie starten via F5 of door te klikken op de groene driehoek. Na deze driehoek kan je nog enkele opties meegeven, kies hierbij voor de combinatie Debug - Win32 (zie Figuur 3) en start vervolgens een debugsessie.
Figuur 3: De configuraties van een project.
Na het ingeven van het eerste getal stopt de uitvoering van het programma. De gele pijl, eveneens in de grijze balk naast de code, geeft de huidige programmapositie aan en staat logischerwijze momenteel op de rode bol. Het meest interessante tabvenster staat afgebeeld in Figuur 4.
Figuur 4: Het debugvenster.
In dit venster krijg je ondermeer een overzicht van: ¾ de waarden van variabelen die binnen de scope liggen van de huidige executielijn. (Autos) ¾ de voor handen zijnde variabelen en hun waarde voor de huidige procedure op de call stack (Locals). ¾ de verschillende threads van het huidige proces (Threads)
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
6
Merk op dat je de waarden van de variabelen gedurende de uitvoer van het programma kan wijzigen via deze vensters. Via de debug-toolbar (Figuur 5), kan je op verschillende manieren het programma doorlopen.
Figuur 5: De debug-toolbar.
De werking van de meeste functies spreekt voor zichzelf. Zo kan je bijvoorbeeld via ‘Step Into’ het programma stap voor stap gaan doorlopen en wel zodanig dat wanneer je een functie tegenkomt, dat deze dan eveneens stapsgewijs wordt doorlopen. Bij ‘Step Over’ zal de gehele functie in 1 keer worden uitgevoerd.
Enkele tips voor het debuggen: ¾ Tijdens het stap voor stap doorlopen zal de console enkel de focus krijgen wanneer er input vereist is door de gebruiker!! ¾ Het programma blijft overzichtelijker indien niet in elke functie (bvb. printf()) wordt ingegaan. Gebruik voor dergelijke regels de ‘Step over’-functie. ¾ Je kan meerdere breakpoints zetten en via ‘Continue’ snel de code tussen de verschillende breakpoints doorlopen.
Experimenteer nu zelf met de debugger en doorloop zeker eens de functie GGD(). Let hierbij op de wijzigingen van de aanwezige variabelen (in Locals)!
Header-bestanden Omdat een C/C++ programma al snel onoverzichtelijk wordt als alle code in 1 enkel bestand staat, gaat men een C/C++ programma typisch opdelen in verschillende bestanden, zogenaamde compilatie-eenheden. Elke compilatie-eenheid correspondeert dan met een module, een logische groepering van functies die samenhoren, zoals bijvoorbeeld een rekenmodule. Daarbij gaat men ook gebruik maken van zogenaamde header-bestanden. Men kan header-bestanden zien als een soort van interfaces waarbij de implementatie ervan wordt overgelaten aan de bronbestanden. De term interfaces is enigszins misleidend omdat het gebruik van header-bestanden, in tegenstelling tot de gekende Java Interfaces, niet van toepassing is op klassen maar wel op functies. Headerbestanden hebben vooral tot doel de overzichtelijkheid van het programma te behouden, herbruikbaarheid van code te vergemakkelijken en het compileren van code te optimaliseren.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
7
Een header-bestand heeft traditioneel de extensie ‘.h’ en kan worden gebruikt via de preprocessor-opdracht ‘#include’. Er zijn hierbij 2 mogelijke notaties (let op de kleine verschillen in notatie): ¾ #include “gebruikergedefinieerd-header-bestand” ¾ #include <standaard-bib-header-bestand> De eeste notatie is typisch voor header-bestanden die door de programmeur zelf worden gedefinieerd. Hiermee duidt men aan dat het header-bestand terug te vinden is in de default-directory voor header-bestanden, dit is in het algemeen ook de directory waar de .cpp-bestanden staan. De tweede notatie geeft aan dat het header-bestand te vinden is in de directory waar ook de header-bestanden van de C++-library staan. (Over het algemeen ga je als programmeur je eigen header-bestanden daar niet neerzetten.) We gaan nu het huidige project zo opsplitsen dat de functie GGD() in een aparte rekenmodule wordt geplaatst.
Maak in de folder ‘Source Files’ een aparte rekenmodule aan via Add- New Item… – Code – C++ File (.cpp). Standaard krijgt het bestand de extensie .cpp, omdat we echter een C-module willen aanmaken, moet de extensie aan de naam worden toegevoegd! (zie Figuur 6)
Figuur 6: Toevoegen van de rekenmodule.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
8
We verplaatsen nu de functie GGD() van het hoofdbestand naar de rekenmodule. Aangezien er in deze functie geen extra bibliotheken worden gebruikt is het niet nodig om in de rekenmodule bepaalde bibliotheken in te voeren.
Vervolgens maken we voor deze rekenmodule een header-bestand aan in de folder ‘Header Files’. In dit header-bestand plaatsen we dan de functieaanroep ‘int GGD(int a, int b);’.
Tot slot rest ons enkel nog het invoegen van dit header-bestand in het hoofdprogramma. Hou er rekening mee dat het hier gaat om een door de gebruiker gedefinieerd header-bestand!
Het programma zou nu opnieuw probleemloos moeten compileren 3 .
Programmeren in C/C++ onder Unix In dit onderdeel wordt nog kort uitgelegd hoe men onder Unix C/C++ applicaties kan maken.
Open een shell op eduserv (Solaris machine), bijvoorbeeld via Putty. Je kan nu je Ccode compileren met behulp van de populaire GNU C-compiler gcc. Voor C++bestanden gebruikt men de GNU C++-compiler g++. Het gebruik van beide compilers is vrij analoog:
¾ Compileren + linken : gcc [-o naamExecutable] *.c (default naam zonder –o is a.out)
¾ Enkel compileren van een bestand : gcc –c [–o naamObj.o] bron.c (default naam zonder –o is bron.o)
¾ Enkel linken : gcc –o naamExecutable *.o
Opmerking: Om comfortabel in C/C++ te programmeren onder Unix (via de commandline mode), werk je best met Makefiles. Meer info over Unix compilers en het gebruik van Makefiles vind je terug op de Minerva website onder de naam unix_makefiles.pdf. Voorts kan je ook heel wat praktische info terugvinden in de manuals van de verschillende tools. Zo vind je bijvoorbeeld via het commando “man gdb” vaak heel vlug alle nodige informatie terug over de GNU debugger. 3
Indien je de foutboodschap “fatal error C1083: Cannot open include file: 'rekenmodule.h': No such file or directory” krijgt, dan is de kans groot dat dit komt omdat het ingevoerde bestand ggd.c zich niet in de projectfolder bevindt.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
9
Het echte programmeerwerk Bereken de vierkantswortel We gaan nu zelf extra functionaliteit implementeren voor de rekencomponent van het ggd-programma uit de Visual C++ inleiding. Het is de bedoeling dat aan deze rekencomponent de mogelijkheid wordt toegevoegd om de vierkantswortel van een willekeurig getal te berekenen. Gebruik voor deze opgave de Newton-Raphson methode voor het berekenen van de vierkantswortel van een positief reëel getal a. Het recursief algoritme:
Men kan aantonen dat xi Æ √a als i Æ ∞.
Voeg dit algoritme toe aan de rekencomponent. Vanuit het hoofdprogramma worden 2 parameters aan dit algoritme meegegeven:
¾ het positief reëel getal a waarvan men de vierkantswortel dient te berekenen. ¾ een drempelwaarde ε (float of double) waarvoor het algoritme stopt als
| xi - xi+1|< ε. Deze 2 parameters worden in het hoofdprogramma door de gebruiker ingegeven. Zorg er tevens voor dat in het hoofdprogramma eerst aan de gebruiker wordt gevraagd welke rekenfunctionaliteit hij precies wil gebruiken (grootste gemene deler of vierkantswortelberekening ). Tips:
¾ voor een correct gebruik van scanf : een float geef je aan met “%f”, een double met “%lf”.
¾ de bibliotheek <math.h> voorziet functies voor het berekenen van de absolute waarde van een getal.
Gebruik, in plaats van je eigen algoritme, de standaardfunctie sqrt( ). Deze functie is eveneens beschikbaar via de bibliotheek <math.h>.
SoftwareOntwikkeling I: Practicum 1 Inleiding MS Visual C++ Programmeren in C/C++
10