• No results found

En jämförande studie av Visual C++, C# och VB.NET

N/A
N/A
Protected

Academic year: 2021

Share "En jämförande studie av Visual C++, C# och VB.NET"

Copied!
159
0
0

Loading.... (view fulltext now)

Full text

(1)

Examensarbete

En jämförande studie av Visual C++,

C# och VB.NET

av

Magnus Krisell

LITH-IDA-EX--05/021--SE

(2)

Examensarbete

En jämförande studie av Visual C++,

C# och VB.NET

av

Magnus Krisell

LITH-IDA-EX--05/021--SE

2005-03-03

Handledare: Johan Fagerström Examinator: Johan Fagerström

(3)

Sammanfattning

Programmeringsspråken Visual C++, C# och VB.NET (Visual Basic.NET) jämförs, med tyngdpunkt på en praktisk jämförelse av fyra exempelapplikationer.

Exempelapplikationen WordCount visar att Visual C++ har förutsättningar för bäst pre-standa, men att även C# och VB.NET ger helt godtagbar prestanda. Valet av färdiga klasser är viktigare än språket. Ett olämpligt val kan göra prestandan mycket sämre än förväntat, medan den allra bästa prestandan ofta erhålls med en egen implementering. Applikationen FFT visar att flyttalsprestandan är bättre i C# än i VB.NET.

Applikationen Clock visar att Visual C++ har en viss fördel i sitt färdiga ramverk för traditionella dokumentbaserade Windowsapplikationer.

C# och VB.NET vinner över Visual C++ i nästan alla övriga avseenden. De ger mind-re mängd kod och tillhandahåller ny funktionalitet — som egenskaper, händelser, attribut och ett mycket omfattande klassbibliotek — som gör programmeringen enklare och mindre känslig för buggar och säkerhetshål. Valet mellan C# och VB.NET bör avgöras av projekt-typ, företagskultur och utvecklarens individuella preferenser.

Abstract

The programming languages Visual C++, C# and VB.NET (Visual Basic.NET) are compar-ed, with emphasis on a practical comparison of four sample applications.

The WordCount sample application shows that Visual C++ has the capability to give the best performance, but also that C# and VB.NET give entirely satisfactory performance. The choice of existing classes is more important than the language. An inappropriate choice can make the performance much worse than expected, while the best performance is often achieved with a custom implementation. The FFT application shows that the floating point performance is better in C# than in VB.NET.

The Clock application shows that Visual C++ has an advantage in its ready-made frame-work for traditional document based Windows applications.

C# and VB.NET beat Visual C++ in almost all other categories. They give less code and provide new functionality — such as properties, events, attributes and a very extensive class library — that makes the development easier and less prone to errors and security breaches. The choice between these two languages should be based on the type of project, corporate culture and individual developer preference.

(4)

Detta examensarbete har utförts vid Institutionen för datavetenskap (IDA) vid Linköpings tekniska högskola och utgör det avslutande momentet i min civilingenjörsutbildning. Jag vill tacka min handledare Johan Fagerström för grundidén till uppgiften. Jag vill också tacka opponent Krister Sjögren för stort tålamod och många värdefulla synpunkter och kommentarer under arbetets gång.

(5)

Innehåll

Innehåll

1 Inledning 9 1.1 Bakgrund . . . 9 1.2 Syfte . . . 9 1.3 Metod . . . 9 1.4 Avgränsning . . . 10 1.5 Förkunskaper . . . 10 1.6 Sammanfattning av resultat . . . 11

2 Microsoft Windows, Visual C++ och Visual Basic 13 2.1 Microsoft Windows . . . 13

2.2 Visual C++ . . . 13

2.3 Visual Basic . . . 14

3 .NET 15 3.1 Vad är .NET? . . . 15

3.2 CLR, Common Language Runtime . . . 16

3.3 FCL, Framework Class Library . . . 16

3.4 C# . . . 17

3.5 Visual Basic.NET . . . 18

3.6 Är .NET bara för Windows? . . . 18

4 Inledande språkjämförelse 21 4.1 Programlistningslayout . . . 21

4.2 Konsolfönsterprogrammet Hello World . . . . 22

4.3 Windowsprogrammet Hello Windows . . . 24

4.3.1 Hello Windows i Visual C++ med MFC . . . . 25

4.3.2 Hello Windows i C# . . . 27

4.3.3 Hello Windows i VB.NET . . . . 29

(6)

5 Allmän språkjämförelse 33 5.1 Primitiva typer . . . 33 5.2 Arrayer . . . 34 5.3 Strängar . . . 35 5.4 Egendefinierade typer . . . 36 5.4.1 Referenstyper . . . 36 5.4.2 Värdetyper . . . 36

5.4.3 Olika former av metodparametrar . . . 37

5.5 Arv och gränssnitt . . . 38

5.5.1 Arv . . . 38

5.5.2 Gränssnitt . . . 39

5.6 Egenskaper . . . 39

5.7 Händelser och delegater . . . 40

5.8 Attribut . . . 40 5.9 Felhantering . . . 43 6 Specifikation av testapplikationer 47 6.1 Clock . . . 47 6.2 WordCount . . . 48 6.3 FFT . . . 49 6.4 Draw . . . 49

6.5 Sammanfattning av huvudsyftet med applikationerna . . . 50

7 Applikationen Clock 51 7.1 Visual C++-versionen . . . 51 7.1.1 CClockApp . . . . 52 7.1.2 CMainFrame . . . . 52 7.1.3 CChildFrame . . . . 53 7.1.4 CClockView . . . 53 7.1.5 CClockDoc . . . . 57 7.1.6 CActivity . . . . 63 7.1.7 CActivitiesDialog . . . . 64 7.2 C#- och VB.NET-versionerna . . . 68 7.2.1 MainForm . . . . 69 7.2.2 ChildWindow . . . . 74 7.2.3 ClockDocument . . . . 79 7.2.4 Activity . . . . 84 7.2.5 ActivitiesForm . . . . 85

(7)

Innehåll

7.3 Jämförelse av versionerna . . . 87

7.3.1 Kodmängd . . . 87

7.3.2 Användande av färdiga klasser . . . 88

7.3.3 Skillnader i grafikhanteringen . . . 89

7.3.4 Kodens struktur och ”renhet” . . . 89

7.3.5 Applikationens funktionalitet och systemkrav . . . 90

8 Applikationen WordCount 91 8.1 C++ . . . 91

8.1.1 ”Simpel” (C++ 1) . . . 92

8.1.2 map och string (C++ 2) . . . 95

8.1.3 hash_map och string (C++ 3) . . . . 97

8.1.4 hash_map och string, version 2 (C++ 4) . . . 98

8.1.5 CMap och CString (C++ 5) . . . . 98

8.1.6 CMap och CString, version 2 (C++ 6) . . . 101

8.1.7 hash_map och CString (C++ 7) . . . 101

8.1.8 CMap och string (C++ 8) . . . 101

8.1.9 hash_map och const char*(C++ 9) . . . 101

8.1.10 CMap och const char*/estring (C++ 10) . . . 102

8.1.11 ”Optimerad” (C++ 11) . . . 102

8.1.12 ”Optimerad”, version 2 (C++ 12) . . . 107

8.1.13 ”Optimerad” med assembler (C++ 13) . . . 107

8.2 C# och Java . . . 108

8.2.1 ”Simpel” (C# 1) . . . 108

8.2.2 Hashtable (C# 2) . . . 111

8.2.3 Java HashMap (Java 1) . . . 113

8.2.4 Dictionary, C# 2.0 (C# 3) . . . 113

8.2.5 ”Optimerad” (C# 4) . . . 114

8.2.6 Java ”Optimerad” (Java 2) . . . 116

8.3 VB.NET (VB) . . . 117

8.4 Jämförelse av de olika versionerna . . . 119

8.4.1 Begränsningar och kompilatorkrav . . . 119

8.4.2 Komplexitet . . . 119

9 Applikationen FFT 123 9.1 C++-versionen . . . 124

9.2 C#-versionen . . . 125

(8)

9.4 VB.NET-versionen . . . 126

9.5 Jämförelse av de olika versionerna . . . 127

10 Applikationen Draw 129 10.1 Visual C++-versionen . . . 129

10.2 C#-versionen . . . 130

10.3 VB.NET-versionen . . . 131

10.4 Jämförelse av de olika versionerna . . . 132

11 Prestandamätningar 133 11.1 Testprocedur . . . 133 11.1.1 Testsystem . . . 133 11.1.2 Kompilatorer . . . 133 11.1.3 Mätning av exekveringstid . . . 134 11.2 WordCount . . . 134 11.2.1 Indatafiler . . . 134 11.2.2 Exekveringstider . . . 135 11.3 FFT . . . 139 11.4 Draw . . . 141 11.5 Sammanfattning av prestandamätningar . . . 142

12 Resultat, diskussion och slutsatser 147 12.1 Prestanda . . . 147 12.2 Kodmängd . . . 147 12.3 ”Buggbenägenhet” . . . 148 12.4 Systemkrav . . . 148 12.5 ”Abstraktionsnivå” . . . 149 12.6 Modularitet . . . 149 12.7 Felhantering . . . 149 12.8 Författarens rekommendation . . . 150

12.9 Riktlinjer för fortsatt arbete . . . 151

Litteraturförteckning 153

(9)

Kapitel 1

Inledning

I detta kapitel tas bakgrunden till arbetet upp, dess syfte, vilken metod som använts och de avgränsningar som gjorts. Lämpliga förkunskaper för att kunna tillgodogöra sig rapportens innehåll berörs och slutligen ges också en sammanfattning av de uppnådda resultaten.

1.1

Bakgrund

Mjukvarubranschen är en ung bransch i konstant förändring. Nya programmeringsspråk och andra verktyg utvecklas ständigt. Det ställs allt högre krav på funktionalitet och robusthet hos de applikationer som ska utvecklas, något som gör tillkomsten av nya språk och verktyg till en nödvändighet för att utvecklingstid och kostnad ska kunna hållas på en rimlig nivå.

Valet står ofta mellan något ”gammalt och beprövat” och något ”nytt och revolutione-rande”. Detta val avgörs av många faktorer. En av dessa bör rimligen vara vilket program-meringsspråk och/eller utvecklingsmiljö som är mest lämpat för den aktuella uppgiften. Detta arbete kommer behandla en avgränsad del av denna frågeställning.

1.2

Syfte

Syftet med detta examensarbete är att studera och jämföra tre av de vanligaste språken för utveckling av applikationer för operativsystemet Microsoft Windows. Språken är Visual C++, C# och VB.NET. Tanken är att det ska gå att dra vissa generella slutsatser om när respektive språk är mest lämpligt att använda, med avseende på sådant som applikationstyp, önskad avvägning mellan prestanda, utvecklingstid och systemkrav.

1.3

Metod

De olika språken studeras och jämförs i första hand med hjälp av fyra exempelapplikationer. Även en kortare genomgång av skillnader i språkens funktionalitet görs. Följande är en uppräkning av de aspekter som speciellt studeras:

(10)

• Prestanda. Hur snabb/långsam blir applikationen?

• Kodmängd. Skiljer sig språken åt i hur mycket kod som behövs för att lösa samma uppgift? Vilken inverkan har de färdiga klasser som finns?

• ”Buggbenägenhet”. Hur stor är risken att misstag vid programmeringen leder till svårfunna fel?

• Systemkrav. Vad krävs för att kunna köra den färdiga applikationen?

• ”Abstraktionsnivå”. Hur mycket stöd finns i språket för de abstraktioner som ofta används i designfasen?

• Modularitet. Har språket särskilt stöd för att smidigt dela upp en applikation i mind-re, fristående delar?

• Felhantering. Vilket är det naturliga sättet att hantera felsituationer?

1.4

Avgränsning

De tre språk1som tas upp är Visual C++, C# och VB.NET. I första hand gäller det som sägs i denna rapport de versioner som ingår i Visual Studio.NET 2003, men i några fall beaktas även Visual C++ 6.0 (från 1998) och beta 1 av Visual Studio 2005 (.NET 2.0, C# 2.0).

Språket Java kommer att tas med i två av exempelapplikationerna. I och med likheten i syntax mellan C# och Java är det mycket lite som i dessa fall behöver ändras för att förvandla ett C#-program till ett Java-program (och vice versa). Men blir prestandan densamma? Även om Java inte tas upp heltäckande i detta arbete studeras denna viktiga aspekt.

Det finns en mängd andra språk och utvecklingsmiljöer för att skriva Windowsapplika-tioner, som t ex Borland Delphi och Visual Basic 6. De tas ej upp i detta arbete.

Valet av språk beror förutom på de andra faktorerna naturligtvis även av vilken typ av applikation som ska utvecklas. Vissa applikationstyper tas inte upp här, t ex spel, drivrutiner, webb- eller serverapplikationer. Detta betyder inte nödvändigtvis att det inte går att tillämpa en del av resultaten också för sådana applikationer. Även all hantering av utskrift på skrivare lämnas vid sidan av arbetet.

1.5

Förkunskaper

Det förutsätts att läsaren har grundläggande kunskaper i C++2 samt känner till något om hur ett modernt operativsystem (inte nödvändigtvis Microsoft Windows) är uppbyggt.

Det förutsätts inte att läsaren tidigare kommit i kontakt med .NET-plattformen eller något av språken C# och VB.NET.

Detta arbete är ganska praktiskt till sin art och teoretiska datavetenskapliga resonemang förekommer ytterst sparsamt, så det bör inte vara några problem att tillgodogöra sig innehål-let för den som uppfyller kraven ovan men i övrigt inte läst några datavetenskapliga kurser på högskolenivå.

1Med ”språk” menas här och i fortsättningen inte enbart själva programmeringsspråket, utan även tillhörande

standardbibliotek och eventuella utökningar specifika för de aktuella varianterna (t ex Visual C++ snarare än standard-C++).

2Om läsaren istället har kunskaper i Java bör det också gå bra att följa med, men det kommer inte förklaras

(11)

1.6. Sammanfattning av resultat

1.6

Sammanfattning av resultat

Här sammanfattas de resultat som erhållits och som diskuteras mer utförligt i kapitel 4–12. • Prestanda. Applikationerna WordCount, FFT och Draw visar att (Visual) C++ ge-nerellt har den högsta prestandan, men också att andra faktorer många gånger har en betydligt större inverkan. Användning av de färdiga klasser som finns för respekti-ve språk ger ofta (men inte alltid) bra prestanda, medan den allra effektivaste koden fås med egen specialanpassad implementering. C# är snabbare än Java. Ett sätt att ytterligare öka prestandan i Visual C++ är att kombinera C++-koden med assembler. • Kodmängd. Allt annat lika ger C# och VB.NET i allmänhet kortare kod än C++. I andra fall beror mängden kod väldigt mycket på vilka färdiga klasser och ramverk som kan utnyttjas.

• ”Buggbenägenhet”. Risken att göra bort sig är väsentligt mindre i C# och VB.NET än i C++. Språken är enklare och innehåller inte lika många potentiellt ”farliga” kon-struktioner.

• Systemkrav. Program skrivna i C# och VB.NET kräver att .NET-ramverket är instal-lerat för att kunna köras, och därmed minst Windows 98. Om en applikation måste kunna köras i Windows 95 eller om det av andra skäl inte går att installera ramverket finns inget alternativ (av de som studerats här) till att använda Visual C++.

• ”Abstraktionsnivå”. C# och VB.NET vinner klart på denna punkt tack vare stöd-et för egenskaper (properties), händelser (events) och gränssnitt (interfaces). Även attribut bidrar till att höja nivån på programmeringen. C++ framstår här som ”efter-blivet”. Det tillhörande klassbiblioteket .NET FCL bidrar ytterligare till att förenkla programmeringen i C# och VB.NET.

• Modularitet. .NET — och därmed C# och VB.NET — är designat från grunden ut-ifrån att en applikation ska kunna sättas samman av fristående binära komponenter. C++ måste kombineras med en teknologi som COM för att ge liknande möjligheter, och det blir då betydligt mer komplicerat.

• Felhantering. Alla tre språken har i sig liknande stöd för strukturerad undantagshan-tering, men i Visual C++ utnyttjas detta dåligt medan det omvända gäller för de båda .NET-språken. Detta ger C# och VB.NET ett klart övertag på denna punkt.

Författaren anser att C# är det bästa språket för att skriva applikationer och klassbibliotek för dagens hårdvara. Prestandan blir i de flesta fall tillräckligt bra, och i de övriga kan interoperabilitet utnyttjas för att skriva enbart de mest tidskritiska delarna i C++. VB.NET ger väsentligen samma möjligheter som C# och passar för den som programmerat i tidigare versioner av Visual Basic.

(12)
(13)

Kapitel 2

Microsoft Windows, Visual C++ och

Visual Basic

I detta kapitel ges en mycket kortfattad introduktion till operativsystemet Microsoft Win-dows och språken Visual C++ och Visual Basic.

2.1

Microsoft Windows

I PC:ns barndom var det textbaserade operativsystemet DOS standard. Detta var helt i har-moni både med dåtidens låga krav på användarvänlighet och med vad den tillgängliga hård-varan var kapabel att utföra till rimlig kostnad. Ett DOS-program har fullständig kontroll över hårdvaran och har samtidigt mycket begränsad hjälp av operativsystemet. Det är inte omöjligt att skriva ett användarvänligt DOS-program, men det innebär mycket jobb. Ett an-nat problem under DOS-eran var att varje program måste ha explicit stöd för alla de olika typer av skrivare och grafikadaptrar som det skulle fungera ihop med.

Windows kom till för att lösa problemen med användarvänligheten och stödet för olika typer av hårdvara. Den första versionen kom 1985 (se t ex [2]) och var väldigt primitiv med dagens mått mätt. Windows var heller inte ensamt om att försöka erbjuda en bättre upplevelse än DOS utan hade flera konkurrenter. Efter en ganska trög start växte Windows i popularitet allt eftersom datorerna blev kraftfullare och nya versioner kom, och från att ha varit ett tillägg blev det vanligt att nya datorer såldes med Windows installerat från början. Även om det idag inte saknas utmanare är Microsoft Windows det i särklass vanligaste operativsystemet för PC-kompatibla datorer och upplevs av många som ”standard”. Det kan näst intill förutsättas att den som äger en PC kan köra Windowsprogram, även om vissa användare föredrar att använda andra operativsystem (som exempelvis Linux).

Den senaste klientversionen av Windows är Windows XP. Den finns i två varianter främst tänkta för hemanvändare (”Home”) resp företag (”Professional”), men dessa de-lar samma kärna till skillnad från tidigare när Windows 95 med efterföljare dominerade i hemmen och Windows NT/2000 på företagen. Detta har gjort det enklare inte minst för programutvecklare.

2.2

Visual C++

Allt sedan den första versionen av Windows har det underliggande API:et (programmerings-gränssnittet) varit baserat på programmeringsspråket C. I början var det enbart möjligt att

(14)

skriva Windowsprogram i C och assembler. När språket C++ började bli populärt på allvar skapade Microsoft ett klassbibliotek kallat MFC (Microsoft Foundation Classes). Detta är i flera avseenden att betrakta som ett tunt skal kring det underliggande API:et, där metoder har fått samma namn som funktionerna och grupperats ihop kring de aktuella strukturerna. Till exempel finns klassen, CWnd för att representera ett fönster.1Den innehåller metoder för att göra olika saker med fönstret. I C-API:et finns istället en struktur som represente-rar fönstret och en uppsättning funktioner som tar en sådan strukturvariabel som argument. MFC gör det möjligt att skriva Windowsapplikationer i C++ på ett objektorienterat sätt.

Nästa nyhet efter MFC var utvecklingsmiljön Visual C++, som underlättar skapandet av applikationer genom att (som namnet antyder) vissa delar av användargränssnittet kan ritas upp grafiskt istället för med programkod. För mer information om den historiska utveck-lingen av MFC och Visual C++ se [1].

Den senast släppta versionen av Visual C++ är Visual C++ 7.1 som ingår i Visual dio.NET 2003. Detta är en mindre uppgradering av version 7.0 som kom med Visual Stu-dio.NET året innan. Den föregående versionen, 6.0, kom 1998 och är den version som varit aktuell under längst tid och under dessa år sågs som något av en standard för att skriva Win-dowsapplikationer i C++. De nyare versionerna innehåller ett begränsat antal nya finesser och version 6.0 (med service pack-uppdateringar) används sannolikt fortfarande i stor om-fattning.

2.3

Visual Basic

Medan C, och senare C++, har varit det ”professionella” valet för att skriva Windowspro-gram — och det som Microsoft själva använt — så insågs också tidigt behovet av ett mer nybörjarvänligt alternativ. Innan Windows slog igenom var det mycket vanligt att opera-tivsystemen levererades tillsammans med en tolk för språket BASIC. Med DOS följde till exempel GW-BASIC. Microsofts QuickBASIC, en kompilerad och förbättrad version av GW-BASIC, blev också mycket populärt i hobby- och nybörjarkretsar.

Första versionen av Visual Basic släpptes i mars 19912 och var resultatet av ett gif-termål mellan QuickBASIC och ett koncept för att visuellt bygga upp användargränssnitt som Microsoft hade köpt av Alan Cooper (allmänt kallad Visual Basics fader). Med Visual Basic blev det för första gången möjligt att skriva Windowsapplikationer utan avancerade programmeringskunskaper.

Det moderna Visual Basic är ett helt nytt språk jämfört med ursprungliga BASIC, men genom att det har behållit namn på nyckelord och en hel del andra karakteristiska drag (t ex att likhetsoperatorn används både för tilldelningar och jämförelser) har den som sedan tidigare är bekant med någon variant av BASIC lättare att komma igång med Visual Basic än med andra språk. Nybörjarvänligheten tycks också bero på att språket använder vanliga engelska ord där C-språken använder ”kryptiska” symboler.

1Ett fönster i Windowsprogrammering är inte enbart det som användaren normalt kallar ett fönster utan även

alla de mindre så kallade kontroller (controls) som användargränssnittet är uppbyggt av.

(15)

Kapitel 3

.NET

I detta avsnitt ges en kortfattad introduktion till .NET (uttalas dotnet, med betoning på net; svenskt namn saknas) och de tillhörande språken C# (uttalas CSharp) och Visual Basic.NET (ofta förkortat till VB.NET). För en mer komplett introduktion, se t ex [10]. För detaljerad information, se [5] eller [17].

3.1

Vad är .NET?

Vad är egentligen .NET? Sannolikheten är stor att läsaren har stött på begreppet men kanske utan att riktigt ha förstått vad det egentligen innebär. Handlar det (som namnet tycks antyda) bara om programmering för webben? Är det Microsofts vision om att leverera programvara som en tjänst istället för som en produkt? Eller är det bara en marknadsföringsterm utan egentlig innebörd? I konceptet finns delar av allt detta inbakat, men .NET är också något konkret. Det är en helt ny plattform för programmering med ett nytt API uppbyggt från grunden enligt objekt- och komponentorienterade principer. .NET är inte knutet till ett visst programmeringsspråk, men två språk har skapats speciellt för att dra nytta av det: C# och VB.NET.

Varför behövs .NET? Vad är problemet med Windows-API:et (kallat Win32-API:et från Windows NT/Windows 95 och framåt) och MFC? En del av problemet har att göra med den tekniska utvecklingen där fokus till stor del har skiftat från separata ”skrivbordsapplika-tioner” till webb- och databasapplikationer och mobila applikationer. .NET-ramverket syftar bl a till att göra det enklare att skriva sådana applikationer. En annan del är att allt eftersom tiden gått så har nya API:n tillkommit i Windows enligt olika modeller. Den grundläggande funktionaliteten finns i det C-baserade Win32-API:et medan nyare funktioner nås via det komponent- och gränssnittsbaserade COM (Component Object Model). Resultatet har blivit en salig röra som gör programmeringen svårare än den skulle behöva vara. Ett specifikt problem är att det saknas ett enhetligt sätt att hantera fel, med resultatet att applikationerna sällan blir så robusta som de borde vara.

Med .NET erhålls en lösning på dessa problem genom ett nytt, enhetligt API som åt-minstone på sikt är tänkt att ersätta allt det gamla. .NET består dels av en körmiljö, kallad CLR (Common Language Runtime, grovt jämförbar med Javas JVM) och dels av ett mycket omfattande klassbibliotek: .NET FCL (Framework Class Library).

(16)

3.2

CLR, Common Language Runtime

CLR:en kan betraktas som en virtuell maskin som (med Just In Time-kompilering) exe-kverar kod i ett format kallat MSIL, Multi-Standard Intermediate Language. En .NET-applikation är uppbyggd av binära moduler (som kan bestå av en eller flera fysiska filer) kallade assemblyn. Ett assembly innehåller kod i MSIL-format1 och dessutom så kallad metadata som beskriver innehållet och vilka andra assemblyn som det aktuella assemblyt behöver för att kunna exekvera. Tack vare metadatan behövs inga separata filer (som h-filerna i C++ eller COM:s IDL-filer) utan varje assembly är helt självbeskrivande. MSIL-kod som exekveras av CLR:en kallas också för hanterad MSIL-kod (managed code), och vanlig processorkompilerad kod kallas följaktligen för ohanterad kod (unmanaged code).2

MSIL (och därmed CLR:en) har stöd för abstraktioner som klasser, egenskaper (pro-perties), händelser (events), gränssnitt (interfaces), arv och polymorfism. Detta innebär att olika programmeringsspråk kan integreras med varandra på ett mycket flexibelt sätt. Det går till exempel att skriva en basklass i C# och ärva från den i VB.NET. Vilket program-meringsspråk som helst kan användas förutsatt att det har en kompilator som kan generera MSIL-kod och att språket har stöd för en bestämd delmängd av CLR:ens funktioner. Detta regleras i det som kallas CLS, Common Language Specification.

En viktig del av CLR:en är minneshanteringen med automatisk skräpupprensning (gar-bage collection). Det minne som allokeras frigörs inte explicit (som med delete i C++) utan kommer automatiskt (vid en obestämd tidpunkt) frigöras av CLR:en efter att den detekterat att objektet inte längre används. Detta innebär en stor lättnad för programmeraren och att flera potentiella buggar elimineras. För en komplett beskrivning av hur skräpupprensningen fungerar se kapitel 19 i [5].

Andra fördelar med CLR:en är att den kan verifiera att programkoden är typsäker och att den inte utför något som den inte har behörighet att utföra. Den har också särskilt stöd för versionshantering. Ett klassiskt problem i Windows är applikationer som slutar fungera för att en annan version av en DLL-fil har installerats. Med .NET går det att garantera att en applikation alltid använder exakt den version av ett assembly som den har utvecklats och testats ihop med. Till skillnad från COM använder inte .NET Windowsregistret för att registrera komponenter (assemblyn). Detta underlättar också både utvecklingen och instal-lationen av den färdiga applikationen.

3.3

FCL, Framework Class Library

Medan CLR:en till stora delar är dold för programmeraren är .NET:s klassbibliotek desto mer synligt. FCL innehåller tusentals klasser och gör det enkelt att skriva många typer av applikationer, som Windowsapplikationer (denna del av FCL kallas Windows Forms), konsolapplikationer, webbapplikationer (Web Forms, ASP.NET), XML-webbtjänster (Web services), databasapplikationer (ADO.NET) och klassbibliotek som kan användas av alla de 1Det är även möjligt att ha ett assembly i ”hybridformat” som också innehåller vanlig maskinkod för datorns

processor. Detta är mycket användbart, men vissa av fördelarna går då förlorade.

2Strikt taget är detta inte helt korrekt. Begreppet hanterad kod bör reserveras för MSIL-kod som också

utnyttjar den automatiska minneshanteringen (skräpupprensningen). Med Microsofts C++-kompilator är det möjligt att kompilera kod i MSIL-format med manuell minneshantering. Detta är dock ovanligt, så i regel begås inget större fel med denna terminologi.

(17)

3.4. C#

andra applikationstyperna.3

Klasserna i FCL är indelade i namnrymder som grupperar ihop typer som hör sam-man. Ofta är en namnrymd implementerad i ett specifikt assembly, men ett assembly kan innehålla flera namnrymder och en namnrymd kan vara utspridd på många assemblyn. Den mest grundläggande namnrymden är System som bland annat innehåller de grundläggan-de datatyper som används av alla applikationer. De andra vanligaste namnrymgrundläggan-derna inleds också med System, t ex System.Collections4 (samlingsklasser), System.Drawing (grafik), System.IO (filhantering), System.Net (nätverkskommunikation), System.Reflection (typer för att dynamiskt undersöka andra typer), System.Runtime.Serialization (för serialisering, dvs lagring och överföring av objekt), System.Text (stöd för olika teckenkodningar m m), System.Threading (klasser för att dela upp en applikation i flera trådar) och System.Xml (klasser för att hantera XML-scheman och XML-data).

Alla typer5ärver på ett eller annat sätt från System.Object. Detta innebär att alla objekt kan betraktas som objekt av klassen System.Object, vilket utnyttjas av samlingsklasserna.

En viktig uppdelning av typerna är mellan och värdetyper. Objekt av referens-typer hanteras alltid av CLR:ens automatiska skräpupprensning, medan objekt av värde-typer kan vara allokerade på stacken. Denna uppdelning är viktig ur prestandasynpunkt. Om alla typer hade varit referenstyper skulle prestandan bli lidande. De primitiva typerna för heltal, flyttal och tecken samt alla uppräkningstyper (enumerations), är värdetyper.

Mer information om typer och vad de kan innehålla ges i avsnitt 5.1–5.7.

3.4

C#

Av det som hittills sagts om .NET framgår inte varför det även behövs ett nytt programme-ringsspråk. Svaret är att ett nytt språk inte är nödvändigt. Det går att skriva kod för .NET även i C++ samt i ett flertal andra språk. En stor fördel med plattformen .NET i jämförelse med Java-plattformen är att den inte är bunden till ett visst språk.

I praktiken finns det dock flera skäl för ett nytt språk helt anpassat för .NET. Program-mering för .NET skiljer sig så pass mycket från traditionell objektorienterad programProgram-mering att C++ i sin standardiserade form inte passar in riktigt. En annan aspekt är att programme-rare ofta tänker i termer av programmeringsspråk, och genom ett nytt språk blir därmed .NET mer konkret, vilket är en fördel också ur marknadsföringssynpunkt. C# betraktas ofta som Microsofts svar på konkurrensen från Java och som ersättaren till Microsofts tidigare Java-plagiat J++.

Som namnet antyder är C#6 relaterat till de äldre språken C och C++. Förhållandet är dock mer komplicerat än mellan dessa två. De flesta C-program går att kompilera med en C++-kompilator, men inga C/C++-program går att kompilera med en C#-kompilator. C# är inte ett tillägg till C++ utan förhållandet mellan C++ och C# är mer som mellan C++ och Java. Den grundläggande syntaxen har behållits, men mycket gammalt har tagits bort samtidigt som mycket nytt har tillkommit. Det officiella syftet med att viss funktionalitet 3Med tillägget Managed DirectX kan även applikationer med hårdvaruaccelererad 3D-grafik (typiskt spel)

skrivas, med enligt Microsoft över 95% av prestandan jämfört med om C++/COM används.

4I .NET 2.0 finns också System.Collections.Generic som innehåller de nya generics-klasserna.

5Orden klass och typ används i denna rapport omväxlande med i stort sett samma innebörd. Enda skillnaden

är att klass inte används för primitiva typer och värdetyper.

6Uttalas CSharp. Vedertaget svenskt namn saknas. Ett logiskt sådant vore Ciss, men risken är att det kan

(18)

tagits bort är att göra C# till ett mindre komplicerat språk än C++. Vissa saker, som pekare, passar heller inte in i .NET:s typsäkra system.

Precis som Java är C# i grunden objektorienterat. Det går inte att skriva ett program som inte innehåller minst en klassdefinition. En annan stor skillnad jämfört med C++ är den automatiska minneshanteringen. Det finns inget delete-nyckelord. C# saknar också pekare7 och mallar (templates)8 och stöder inte multipelt arv. I gengäld innehåller C# nya abstrak-tioner som egenskaper (properties), händelser (events), gränssnitt (interfaces) och attribut. Flera andra mindre utökningar har också gjorts, och fler fördelar fås genom den intima kopplingen till .NET och dess omfattande klassbibliotek.

3.5

Visual Basic.NET

I och med den stora popularitet som Micrsofts Visual Basic-språk har skaffat sig var det naturligtvis otänkbart att Microsoft skulle överge detta språk. Visual Basic.NET9är Visual Basic för .NET. Syntaxen har så långt det varit möjligt behållits från tidigare versioner, men för att kunna samarbeta obehindrat med .NET-arkitekturen och dess klassbibliotek har stora förändringar gjorts. VB.NET är ett fullt objektorienterat språk med samma möjligheter som C#. Bortser man från den annorlunda syntaxen är likheterna mycket större än skillnaderna. Några skillnader finns trots allt. VB.NET har ingen motsvarighet till C#:s osäkra lä-ge och stöder inte operatoröverlagring. Språket har inga nyckelord för de teckenlösa (un-signed) heltalen (men det går att använda FCL-typerna för dessa). Ingen åtskillnad görs mellan versaler och gemener, vilket kan påverka namngivningen av metoder och variab-ler. VB.NET har å andra sidan några konstruktioner som saknas i C#, som en smidigare syntax för händelsehantering och möjlighet att för enkla program gömma undan objekt-orienteringen. En del av den funktionalitet som finns i klassbiblioteket har också av bakåt-kompatibilitetsskäl separata funktioner i VB. Detta kan göra koden lite svårare att förstå för en C#-programmerare, men underlättar för VB-programmerare.

I praktisk användning uppstår ofta andra skillnader som har att göra med hur IDE:n (utvecklingsmiljön, Visual Studio.NET) och kompilatorerna beter sig. I Visual Studio.NET 2003 har Microsoft lagt mer krut på att göra texteditorn smart för VB än för C#. I och med att långa nyckelord ofta används där C# använder enstaka tecken kan man också se det som att behovet av att underlätta kodskrivandet är större i VB än i C#.

I och med VB.NET är Visual Basic för första gången ett språk på samma nivå som de C-baserade språken. Det finns ingen konkret anledning till att en applikation skriven i VB.NET skulle vara sämre än en skriven i C# (se dock prestandamätningarna i avsnitt 11.3).

3.6

Är .NET bara för Windows?

.NET har utvecklats av Microsoft och deras implementation exekverar logiskt nog bara un-der Windows. Flera delar har dock standardiserats av ECMA (se [11]) och flera projekt för 7Detta är inte helt sant. I så kallad osäkert (unsafe-) läge kan pekare användas i C#. Detta används dock bara

i speciella fall och CLR:en kan då inte verifiera att koden är typsäker.

8Detta är en begränsning, men i C# 2.0 (.NET Framework 2.0) — i skrivande stund i beta — är en av

ny-heterna så kallade generics, som inte fungerar exakt som mallar i C++ men löser flera av samma problem och är smidigare att använda.

9Förkortas oftast till bara VB.NET, eller enbart VB när det av sammanhanget framgår att det är VB.NET

(19)

3.6. Är .NET bara för Windows?

att implementera CLR:en för andra operativsystem har startats.10En ren .NET-applikation som inte utnyttjar interoperabilitet11eller någon av de Microsoft-specifika klasserna är där-med potentiellt operativsystemsoberoende på samma sätt som en Java-applikation.

Det finns också en nedbantad version av .NET-ramverket kallad .NET Compact Frame-work för mobila enheter (handdatorer och avancerade mobiltelefoner). Ett av syftena bakom .NET är att göra det enklare att skriva applikationer för sådana enheter.

Svaret är alltså: Nej, .NET är inte enbart för Windows, även om det är just för Windows-programmering som det är som mest aktuellt och det som studeras i det här arbetet.

10Två exempel är DotGNU (www.dotgnu.com) och Mono (www.go-mono.com).

11Denna term (ibland förkortad till bara interop) används för att beskriva fallet att en .NET-applikation också

anropar funktioner i Win32-API:et, använder COM-objekt eller på annat sätt utnyttjar programkod som inte skrivits för .NET.

(20)
(21)

Kapitel 4

Inledande språkjämförelse

I detta kapitel studeras ett par mycket enkla exempel som visar på grundläggande skillnader mellan språken. För mer detaljer hänvisas till kapitel 5 samt till referensdokumentationen för respektive språk ([9], [18]) eller någon av de många böcker som skrivits om dem (t ex [5], [3] och [6]).

4.1

Programlistningslayout

I detta och de följande kapitlen kommer programlistningar visas. För att göra dessa lättlästa används en layout med färgkodning1och med markering av vilket språk programkoden är i. Denna layout förklaras här:

• Radnumren ingår inte i själva koden utan är bara till för att i texten enkelt kunna referera till delar av koden.

• Blankrader används för att göra koden mer lättläst.

• Klamrarna,{och}, placeras på egna rader och vertikalt under varandra.

• Textdelarna av koden (utom literaler) skrivs med ett proportionellt typsnitt, detta för att göra koden lättare att läsa och minska antalet ologiska radbrytningar.

• Färgmarkering görs enligt följande:

– Nyckelord anges med blå färg:while,Integer

– Literaler, dvs textsträngar, tecken och tal, markeras med ljuslila färg:16384 – Namn på namnrymder, klasser/typer, gränssnitt, metoder, funktioner,

egenskap-er och händelsegenskap-er som inte definiegenskap-eras i den egna koden utan ses som ”extegenskap-erna element” markeras med blågrön färg:System,CDialog,sin

– Klasser/typer och namnrymder som definieras i den egna koden markeras med orange färg:CActivity,ClockDocument

– Kommentarer markeras med mörkgrönt och i ett annat typsnitt:// Rita linje – Övriga delar av koden (egna metoder, fält, egenskaper, lokala variabler,

kon-stanter, makron, operatorer etc) skrivs med svart färg: OnPaint, rect,== 1Färgversionen av rapporten finns att hämta i PDF-format på exjobbets webbsida:

(22)

• Programlistningens språk visas med en markering i nedre högra hörnet. Syftet med denna markering är främst att man vid en snabb bläddring i rapporten direkt ska kunna se vilket språk en viss kodlistning är i. C++ och C# kan annars vid en hastig blick vara förvillande lika varandra.

• En programlistning som fortsätter på nästa sida markeras med en pil längst ner. • När bara enstaka rader programkod visas används inte radnumren eller

språkmarke-ringen.

• När kodtermer nämns i texten används samma stil som i listningarna men alltid i svart. Undantaget är i sakregistret där färgerna används.

4.2

Konsolfönsterprogrammet Hello World

Först studeras ett mycket enkelt program som inte gör mer än att skriva ut texten ”Hello World!” i ett konsol-/kommandofönster. Även om den typen av program mest är förknippad med DOS- och UNIX-miljöer går det utmärkt att skriva och köra sådana program även under Windows.

C++-versionen är likadan som i t ex UNIX:

#include <iostream>

using namespace std; void main()

{

cout << "Hello World!" << endl; } 1 2 3 4 5 6 7

C++

Detta program kompileras med Visual C++ som en konsolapplikation och exekverar som man förväntar sig.

Skrivet i C# får Hello World följande utseende:

using System; class HelloWorld

{

static void Main()

{

Console.WriteLine("Hello World!");

} } 1 2 3 4 5 6 7 8 9

C#

C#-versionen skiljer sig en del från sin motsvarighet i C++ och man ser tydligt den objekt-orienterade strukturen. Den som har programmerat i Java känner igen detta. System är en namnrymd där klassen Console är definierad. Om raden med using System togs bort skulle man behöva skriva:

System.Console.WriteLine("Hello World!");

(23)

4.2. Konsolfönsterprogrammet Hello World

std::cout << "Hello World!" << std::endl;

om using namespace utelämnades. Det vanligaste är att using-deklarationerna används för att inte upprepade gånger behöva ange namnrymden för ofta använda klasser.

WriteLine är en statisk metod i klassen Console. Statisk betyder samma sak som i C++, dvs att metoden tillhör själva klassen och att det inte behövs något Console-objekt för att anropa den. Det som anges till vänster om punkten är då klassnamnet. C# använder punkt där C++ använder dubbelkolon.

Någon direkt motsvarighet till #include-direktivet finns inte. Tack vare att kompilatorn använder metadatan i .NET-assemblyna behövs inga headerfiler i C#. All källkod skrivs därmed ”inline” på samma sätt som i Java. C#:s källkodsfiler har filändelsen cs och en fil kan innehålla flera klassdefinitioner.2 Däremot går det inte att dela upp en klassdefinition på flera filer.3

C# är i likhet med C och C++ ett språk som gör skillnad på gemener och versaler. Main i C#-programmet måste heta exakt så, precis som main måste heta exakt så i C++. Att skapar-na av C# valt att använda versal är i linje med det rekommenderade skapar-namngivningsmönstret för .NET, där publika klasser och metoder ska inledas med versal (se [16]). Main betraktas alltid som publik eftersom den anropas av CLR:en när programmet startas.

På liknande (men inte exakt samma) sätt som i C++ kan man också definiera Main att ta parametrar som används för att få information om kommandoradsargument. Hur detta går till visas i samband med applikationen WordCount (se kapitel 8).

I VB.NET kan programmet skrivas på två sätt, antingen:

Imports System Class HelloWorld

Shared Sub Main()

Console.WriteLine("Hello World!")

End Sub End Class 1 2 3 4 5 6 7

VB

eller: Module HelloWorld Sub Main()

Console.WriteLine("Hello World!")

End Sub End Module 1 2 3 4 5

VB

Den första versionen är helt analog med C#-programmet. VB använder nyckelordet Imports istället för using och Shared istället för static, och metoder som inte returnerar något värde markeras med Sub. Källkoden skrivs i filer med ändelsen vb med samma regler som för C#. Till skillnad från C++ och C# bryr sig VB inte om gemener och versaler. Texteditorn i Visual Studio.NET har synpunkter på hur koden ska se ut och använder automatiskt versaler på alla nyckelord. Denna konvention används också i den här rapporten, men för kompila-torns del har det ingen betydelse. En annan skillnad är att inte semikolon eller något annat 2Det finns inte som i Java någon obligatorisk koppling mellan filnamnet och namnet på den eller de klasser

som definieras i filen.

(24)

tecken används för att avsluta en sats. Istället fyller radbrytningen den funktionen. Program-meraren har därmed mindre frihet i programkodens utformning, men en fördel är att koden blir mer enhetlig. Om en sats är för lång för att rymmas på en rad kan den fortsätta på nästa om den föregående avslutas med _ (understrykningstecken).

Den andra versionen döljer objektorienteringen bakom det modulkoncept som VB.NET behåller från tidigare versioner av Visual Basic. Main ser då ut som en vanlig procedur och man varken behöver eller får ange Shared. Imports System behövs inte heller. I själva verket kan denna rad tas bort också i den första versionen eftersom kompilatorn förutsätter att man alltid vill ha smidig tillgång till klasserna i namnrymden System. Raden togs med för att visa på likheten med C#-versionen.

Vid kompileringen kommer båda versionerna att generera identisk MSIL-kod (även om det blir vissa skillnader i metadatan). Detta kan konstateras med verktyget ILDASM som medföljer utvecklingsmiljön för .NET.

I fortsättningen av denna rapport (utom för applikationen FFT, se kapitel 9) kommer VB-kod skrivas på det objektorienterade sättet.

4.3

Windowsprogrammet Hello Windows

I detta avsnitt studeras en mycket enkel Windowsapplikation. Programmet öppnar ett fön-ster och skriver ut texten ”Hello Windows!” i övre vänstra hörnet. Ett Windowsprogram (eller ett program för något annat någorlunda modernt operativsystem) skiljer sig från ett konsolfönsterprogram (eller ett gammalt DOS-program) speciellt i två viktiga avseenden: hur programmet tar emot information från användaren och hur det presenterar sitt resultat på skärmen.

När ett konsolfönsterprogram behöver information från användaren visar det ett med-delande och stannar exekveringen tills användaren knappat in informationen. Programmet skriver ut sitt resultat med start på nästa rad i konsolfönstret. Allt händer i en sekvens som man kan följa genom att studera källkoden.

Ett Windowsprogram kan inte anropa en funktion som gör att programkörningen stan-nar och väntar på användaren. Anledningen är att programmet kan behöva göra andra saker under tiden. Det kan heller inte skriva ut sitt resultat på skärmen bara vid de tillfällen pro-grammeraren bestämmer utan måste vara berett att göra det när Windows begär det.

Det här innebär att ett Windowsprogram får en annorlunda struktur jämfört med ett konsolfönsterprogram. Operativsystemet anropar programmet istället för tvärtom.4 Detta brukar kallas att operativsystemet skickar ett meddelande till programmet. Applikationen blir strukturerad som en uppsättning meddelandehanteringsfunktioner.

Det enkla program som används som exempel här kräver ingen inmatning från använ-daren för att skriva ut sitt resultat men meddelandehanteringen kommer in i bilden ändå. Texten som skrivs ut i fönstret måste kunna skrivas ut upprepade gånger på begäran av Windows. Detta är nödvändigt för att texten ska stanna kvar när användaren ändrar stor-lek på fönstret eller flyttar runt andra fönster på skärmen. Windows sparar inte innehållet i ett övertäckt eller minimerat fönster. Meddelanden används också för annat som har med fönstret att göra, t ex när det aktiveras, när storleken ändras eller när användaren klickar i stängningsrutan. Vid behov kan dessa meddelanden fångas och hanteras i programmet. 4Naturligtvis gör även ett Windowsprogram anrop till funktioner hos operativsystemet, men inte för den

(25)

4.3. WindowsprogrammetHello Windows

(Stängningen kommer hanteras i exemplet här, även om det inte syns i programkoden ef-tersom det sker i basklasserna.)

4.3.1 Hello Windows i Visual C++ med MFC

Det naturliga sättet att skriva ett Windowsprogram i Visual C++ är att använda klassbib-lioteket MFC (se sid 14). MFC är lite mer än bara ett klassbibliotek eftersom det (när det används fullt ut) också bestämmer grundstrukturen hos programmet och brukar därför kallas för ett applikationsramverk (Application Framework). Ett alternativ till att använda MFC är att använda det råa Win32-API:et. Detta kommer inte göras i den här rapporten, men för ett exempel på hur ”Hello Windows” skulle se ut då, se sid 22–23 i [2].

MFC-versionen ser ut så här:

// MFC-header-fil

#include <afxwin.h>

class CHelloWindowsApp : public CWinApp {

public:

// Omdefinierad virtuell metod

BOOL InitInstance();

};

class CHelloWindowsFrame : public CFrameWnd {

public:

CHelloWindowsFrame();

protected:

// Meddelandehanteringsmetod

afx_msg void OnPaint();

// Makro för meddelandehanteringen (se texten)

DECLARE_MESSAGE_MAP()

};

// Det globala CWinApp-objektet

CHelloWindowsApp application;

BOOL CHelloWindowsApp::InitInstance()

{

m_pMainWnd = new CHelloWindowsFrame();

m_pMainWnd->ShowWindow(m_nCmdShow);

m_pMainWnd->UpdateWindow();

return TRUE; }

// Makron för meddelandehantering

BEGIN_MESSAGE_MAP(CHelloWindowsFrame, CFrameWnd)

// Hantera WM_PAINT-meddelanden ON_WM_PAINT() END_MESSAGE_MAP() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

C++

(26)

CHelloWindowsFrame::CHelloWindowsFrame()

{

// Skapa fönstret

Create(0, "Hello Windows");

}

void CHelloWindowsFrame::OnPaint()

{

// Enhetsmiljöobjekt för att rita i fönstret

CPaintDC dc(this);

dc.TextOut(0, 0, "Hello Windows!");

} 41 42 43 44 45 46 47 48 49 50 51 52 53

C++

Jämfört med konsolfönsterprogrammet blir detta längre och lite mer komplicerat, men ändå betydligt kortare än vad ett klassiskt Windowsprogram utan MFC skulle vara. Detta enkla program utnyttjar inte MFC-ramverket fullt ut utan bara så mycket som behövs för att programmet ska kunna utföra sin uppgift.

En MFC-applikation innehåller alltid en global variabel av en klass ärvd från CWinApp. Klassen i detta fall är CHelloWindowsApp5och variabeln återfinns på rad 25. Den används av ramverket för att starta programmet. main (eller snarare WinMain som startfunktio-nen heter i ett Windowsprogram) är inbakad i ramverket och syns inte här. Den första rad i programmet som exekveringen kommer hamna på är rad 27. Den virtuella metoden InitInstance anropas av ramverket när applikationen startar, och vad programmet gör av-görs av en omdefinierad (overridden) version av denna metod.

I detta fall sätts m_pMainWnd till en ny instans av klassen CHelloWindowsFrame. m_pMainWnd är ett skyddat (protected) fält i CWinApp och ska innehålla en pekare till programmets huvudfönster. Huvudfönstret har en speciell ställning i kommunikationen med Windows. Efter att fältet satts anropas metoderna ShowWindow och UpdateWindow som visar fönstret och uppdaterar dess innehåll. ShowWindow tar som argument ett heltalsvärde som kan användas för att bestämma vissa egenskaper hos fönstret, t ex om det ska vara maxi-merat. I exemplet används fältet m_nCmdShow som innehåller ett lämpligt standardvärde. Slutligen returneras TRUE för att indikera att initialiseringen varit framgångsrik.

Det är av historiska skäl som datatypen BOOL används och inte C++ inbyggda bool. Det går att kompilera och få korrekt beteende med true istället för TRUE, men det fungerar inte att deklarera InitInstance så att den returnerar bool istället för BOOL (eftersom metodens signatur och returtyp måste överensstämma med basklassens).

Resten av programkoden utgör definitionen av klassen CHelloWindowsFrame som re-presenterar programmets fönster. Denna klass ärver från MFC-klassen CFrameWnd som är basklassen för en applikations huvudfönster (och som i sin tur ärver från CWnd). En kon-struktor och en metod definieras samt DECLARE_MESSAGE_MAP(). Detta är ett makro som behövs för MFC:s meddelandehantering. För detaljer kring denna hänvisas till [13] el-ler [1]. Makrot måste finnas med i definitionen av alla klasser som hanterar meddelanden.

Till implementeringen används på rad 36–40 de båda makrona BEGIN_MESSAGE_-MAP och END_MESSAGE_BEGIN_MESSAGE_-MAP. BEGIN_MESSAGE_BEGIN_MESSAGE_-MAP tar två argument som är namnen på aktuell klass och dess basklass. Inuti makroparet anges vilka meddelanden som ska hanteras. Det finns ett generellt makro kallat ON_MESSAGE som tar två argument:

(27)

4.3. WindowsprogrammetHello Windows

meddelandet som ska hanteras och namnet på den metod som då ska anropas. För vissa speciella meddelanden finns mer specifika makron som förenklar; ett exempel på det är ON_WM_PAINT.

Metoden OnPaint kommer att anropas när Windows skickar ett WM_PAINT-delande. OnPaint är en vanlig icke-virtuell metod. Det är en konvention att markera med-delandehanteringsmetoder (meddelandehanterare) med afx_msg. Detta makro har egentli-gen inegentli-gen funktion och koden ovan kompilerar och exekverar lika bra om det utelämnas. Det tjänar dock som minneshjälp för programmeraren och används också av Visual Studio-IDE:n.

I konstruktorn till CHelloWindowsFrame anropas metoden Create som skapar själva fönstret. Denna metod tar ett antal argument med standardvärden som vid behov kan ändras. Här används bara de två första.

Slutligen implementeras metoden OnPaint, som ser till att det händer något utöver att ett tomt fönster visas. Ett objekt av klassen CPaintDC skapas med en konstruktor som tar en pekare till det aktuella fönstret (ett objekt av en klass ärvd från CWnd) som argument. I CPaintDCs konstruktor anropas CWnd-metoden BeginPaint. CPaintDC har också en de-struktor som anropar metoden EndPaint. I och med att objektet skapas på stacken kommer destruktorn att köras just innan OnPaint returnerar.

Förfarandet med BeginPaint och EndPaint har att göra med hur uppdateringen av fönsterinnehållet går till. WM_PAINT-meddelanden genereras så snart någon del av fön-stret behöver ritas om, vilket brukar kallas att den blivit ogiltig (invalid). Med anropet till BeginPaint erhålls information om vilken del av fönstret som behöver ritas om. Ritopera-tioner utanför denna area kommer att ignoreras, vilket snabbar upp ritningen. CPaintDC har ett publikt fält vid namn m_ps av typen PAINTSTRUCT som ger tillgång till denna information. Den ignoreras av Hello Windows i likhet med av många andra enkla program där det inte finns något behov av att optimera grafikprestandan.

Klassen CPaintDC är ärvd från den mer generella CDC som representerar ett Windows-objekt som kallas för enhetsmiljön (device context, DC). Grafikdelen av Win32-API:et kal-las för GDI (Graphics Device Interface). Med GDI kan ett program rita (tvådimensionell) grafik och text i ett fönster utan kännedom om vilket grafikkort datorn har och skriva ut på skrivare utan att veta vilken typ av skrivare som används. Klassen CDC har ett antal metoder som svarar direkt mot GDI-funktionerna i Win32-API:et. I detta exempel används metoden TextOut för att rita texten ”Hello Windows!” vid koordinaterna (0, 0). Koordinaterna är i pixlar (om detta inte ändras, vilket går att göra med andra metodanrop) och räknas från övre vänstra hörnet av fönstrets så kallade klientarea (även detta kan ändras). Klientarean är den del av fönstret som inte ritas upp av Windows, dvs exklusive titelraden, kanten och eventuell meny.

I och med att OnPaint anropas varje gång ett WM_PAINT-meddelande genereras och att detta sker så snart någon del av fönstret blivit ogiltig kommer texten skrivas ut så ofta som behövs för att stanna kvar i fönstret efter att det varit övertäckt eller minimerat.

4.3.2 Hello Windows i C#

(28)

using System;

using System.Drawing; using System.Windows.Forms;

// Fönsterklass ärvd från System.Windows.Forms.Form

class HelloWindowsForm : Form {

static void Main()

{

Application.Run(new HelloWindowsForm());

}

// Privat konstruktor (se texten)

HelloWindowsForm()

{

// Sätt egenskaper hos fönstret

BackColor = SystemColors.Window; Text = "Hello Windows"; }

// Omdefinierad metod för ritningen

protected override void OnPaint(PaintEventArgs e)

{

e.Graphics.DrawString("Hello Windows!", Font, SystemBrushes.WindowText, 0, 0);

} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

C#

Det normala sättet att skapa ett applikationsfönster i C# är att definiera en klass som ärver från klassen Form som återfinns i namnrymden System.Windows.Forms. Eftersom det en-bart finns publikt arv i .NET (se avsnitt 5.5.1, sid 38) anges inget public, utan enen-bart ett ko-lon och namnet på basklassen. Den nya fönsterklassen får här namnet HelloWindowsForm. Programkörningen startar som i konsolfönsterprogrammet Hello World genom att me-toden Main anropas. Det har ingen betydelse i vilken klass Main placeras. Här har den av praktiska skäl placerats i fönsterklassen. Det är även möjligt att ha flera Main-metoder (i olika klasser) om man talar om för kompilatorn vilken som ska användas.

I Main görs här en enda sak: Den statiska metoden Run i klassen System.Application anropas med en nyskapad instans av HelloWindowsForm som argument. Nyckelordet new används precis som i C++ för att skapa nya objekt. Dessa objekt hanteras av CLR:en som efter att objekten inte längre behövs automatiskt frigör det minne de använder. De finns alltså ingen motsvarighet till C++ delete.

Application.Run placerar programmet i en meddelandeslinga och allt sker därefter på kommando av meddelanden som operativsystemet (eller applikationen själv, eller en annan applikation) skickar. Det är detta metodanrop som förvandlar programmet från ett konsol-fönsterprogram till ett Windowsprogram. Run returnerar när programmets huvudfönster (det som skickades med som argument) stängs, och i detta fall avslutas då programkörning-en. Inget hindrar att andra operationer utförs i Main före och efter anropet till Run.

HelloWindowsForm har en konstruktor vars definition börjar på rad 14. I och med att inget annat anges kommer konstruktorn bli privat (private), vilket innebär att det bara går att skapa objekt av klassen i metoder som tillhör klassen. Detta fungerar bra här eftersom

(29)

4.3. WindowsprogrammetHello Windows

Main är en metod i samma klass.6

I konstruktorn sker två saker. Ingen av dessa är helt nödvändig för att programmet ska fungera och om de utelämnas kan hela konstruktordefinitionen utelämnas. För att fönstret ska se likadant ut som i C++-versionen behöver bakgrundsfärgen ändras. Fönstret ges också en lämplig titel. Detta görs med något som ser ut att vara tilldelningar till fält. I själva verket är de inga fält utan så kallade egenskaper (properties). Egenskaper är egentligen (par av) metoder men anropas med fältsyntax (se avsnitt 5.6, sid 39).

Precis som i C++-programmet finns en metod med namnet OnPaint. Som syntaxen säger rör det sig i detta fall om en virtuell metod som omdefinieras. Det är nödvändigt att ange override-nyckelordet för att tala om att metoden är en omdefinierad metod. Skulle detta utelämnas kommer kompilatorn förutsätta att metoden inte är en omdefiniering utan en ny metod som bara råkar ha samma namn. Detta kan anges explicit med nyckelordet new (och om detta inte görs kommer kompilatorn ge en varning). Vitsen med det här och hur det löser ett problem som finns i C++ förklaras i avsnitt 5.5.1. Det är också nödvändigt att metoden har samma synlighet som basklassens, varför protected (med samma betydelse som i C++) används.

OnPaint är definierad i klassen Control som Form ärver från via klasserna Container-Control och ScrollableContainer-Control (alla i namnrymden System.Windows.Forms). Container-Control har ett stort antal virtuella metoder varav många är knutna till Windowsmeddelanden som WM_MOUSEMOVE, WM_PAINT etc. Ett sätt att fånga dessa meddelanden är således att omdefiniera motsvarande metod. Ett annat sätt är att använda C#:s/.NET:s händelsehan-teringsmekanism som behandlas vidare i avsnitt 5.7, sid 40.

I den omdefinierade OnPaint skrivs texten ut med hjälp DrawString som är en metod i klassen System.Drawing.Graphics. Denna klass fyller samma funktion som CDC gör i MFC. .NET använder inte GDI utan istället GDI+. GDI+ är inte exklusivt för .NET utan kan användas även från ohanterad C++. Där är detta dock relativt besvärligt medan det i C# är det naturliga valet.7

Det Graphics-objekt som behövs följer med som en egenskap i PaintEventArgs-para-metern. DrawString finns i sex överlagrade versioner. Alla kräver förutom texten och dess position att typsnitt och pensel skickas med. Som typsnitt används här Font som är en egenskap hos Form, och som pensel SystemBrushes.WindowText. WindowText är en sta-tisk egenskap hos klassen SystemBrushes (i namnrymden System.Drawing) och vilken den faktiska färgen blir beror på användarens inställningar i Windows (normalt svart).

4.3.3 Hello Windows i VB.NET

När programmet skrivs i VB kommer det se ut så här:

6I och med att applikationen kompileras till ett .NET-assembly finns möjligheten för andra assemblyn att

referera till och skapa instanser av dess typer. En privat konstruktor innebär att ingen kod i ett annat assembly kan skapa HelloWindowsForm-objekt, vilket däremot är möjligt om konstruktorn är publik. Således kan det ha betydelse om en metod är publik eller privat, även om det inte spelar någon roll inom den aktuella applikationen.

7GDI kan användas från C# (och VB.NET) med hjälp av interop, vilket det av prestandaskäl kan finnas

(30)

Class HelloWindowsForm

Inherits Form

// Publik konstruktor (se texten)

Sub New()

BackColor = SystemColors.Window Text = "Hello Windows"

End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

e.Graphics.DrawString("Hello Windows!", _ Font, SystemBrushes.WindowText, 0, 0)

End Sub End Class 1 2 3 4 5 6 7 8 9 10 11 12 13 14

VB

Detta program är till strukturen mycket likt C#-programmet, vilket är naturligt eftersom bå-da använder samma basklass i .NET-ramverket. Ändå syns en del skillnader. I VB-program-met behövs ingen Main-funktion. Kompilatorn utgår ifrån att programVB-program-met ska startas på ett ”standardmässigt” sätt och lägger själv till den kod (ekvivalent med den i C#-programmet) som behövs. Det går dock bra att istället lägga till Main manuellt, så flexibiliteten offras inte.

I övrigt kan man lägga märke till VB:s syntax för arv (nyckelordet Inherits; detta måste stå på ny rad), för konstruktorer (New) och för att deklarera metoder och metodparametrar. Metoder deklareras med nyckelordet Sub eller Function, beroende på om något värde re-turneras eller inte. ByVal används för att skicka ett arguments värde och är det vanliga fallet som inte kräver någon speciell syntax i C#. Motsatsen är ByRef där en referens skickas istället (se avsnitt 5.4.3, sid 37).

En detalj i samband med konstruktorn är att den blir publik. VB använder till skillnad från C# Public om inget annat anges. För att koden mer exakt ska motsvara C#-versionen kan man lägga till Private före Sub New.

Anropet till Graphics.DrawString ser likadant ut som i C#-programmet. Samma syntax används vid metodanrop och för egenskaper, och den enda skillnaden är att understryk-ningstecknet måste anges för att få satsen att fortsätta på nästa rad.

4.3.4 Jämförelse av versionerna

Jämför man de tre versionerna av Hello Windows finns en del saker att lägga märke till. C#- och VB-versionerna är avsevärt kortare än Visual C++-versionen och har framför allt en mycket renare objektorienterad struktur. Visual C++-versionen är beroende av makron för meddelandehanteringen, CWinApp-klassen innehåller publika fält som måste användas och det behövs en global variabel. Dessutom kan det upplevas förvirrande att man inte enkelt ser var någonstans programkörningen börjar. Andra skillnader kan betraktas som mer ”kosmetiska”.

Måste Visual C++-versionen vara så komplicerad? Varför behövs strulet med meddelan-dehanteringsmakrona? Skulle inte OnPaint kunna vara en virtuell metod precis som den är i .NET-ramverket? Svaret på denna fråga är inte helt uppenbart. På sid 26–27 i [1] förklaras att antalet virtuella metoder då skulle bli så stort att det skulle krävas en virtual dispatch-tabell på ca 440 byte för varje klass ärvd från CWnd. Detta var nog ett större problem när MFC skapades i början av 1990-talet än vad det skulle vara idag, men det nämns också att

(31)

4.3. WindowsprogrammetHello Windows

även om meddelandehanteringen för Windowsmeddelandena skulle använda virtuella me-toder skulle det krävas något annat för att hantera meddelanden från t ex menykommandon. Grundproblemet är att språket C++ saknar en inbyggd mekanism för händelsehantering. Meddelandehanteringen med makron behöver inte i sig vara något problem, men det är svårt att förneka att den försämrar läsbarheten hos ett exempelprogram av det här slaget om läsaren är bekant med objektorientering men inte kommit i kontakt med Visual C++ tidigare.

C#-versionen har fördelen att man enkelt kan se var exekveringen börjar. Man får en ganska komplett bild av hur programmet fungerar, trots att mycket av grundfunktionaliteten är ärvd från basklassen Form. I VB-versionen är en del av detta dolt genom att Main saknas. Det framgår heller inte vilka namnrymder som används. Eftersom detta är sådant som man kan lägga till om man vill så det dock är svårt att betrakta detta som en nackdel hos VB i jämförelse med C#. Snarare är det en fördel att dessa element kan utelämnas och därigenom ge ett märkbart kortare program. Vilket av dessa två språk som är mest läsbart torde bero på programmerarens erfarenhet och preferenser.

Studeras enbart OnPaint-metoden kan man notera skillnader i hur koden får tillgång till CDC- (CPaintDC-) respektive Graphics-objektet och hur utskriften av texten går till. I Visual C++-versionen skapas CDC-objektet på stacken medan .NET-versionerna får sitt Graphics-objekt levererat inuti en parameter. I anropen till TextOut respektive DrawString ser man skillnaden att DrawString vill ha mer fullständig information om hur texten ska ritas; typsnitt och pensel måste skickas med. Motsvarande val i Visual C++-versionen skulle göras genom att anropa andra CDC-metoder före TextOut. Detta är en allmän skillnad mellan GDI och GDI+ och ligger bakom att GDI+ ibland kallas tillståndslöst (vilket dock bara gäller delvis eftersom annat som kan påverka textens utseende anges med separata metodanrop).

(32)
(33)

Kapitel 5

Allmän språkjämförelse

I detta kapitel görs en kortfattad genomgång av grundläggande funktionalitet som används i senare kapitel. Som angavs i avsnitt 1.5 förutsätts det att läsaren är bekant med C++ och beskrivningen är därför koncentrerad till det som skiljer sig i C# och VB.NET.

5.1

Primitiva typer

Alla språken har fördefinierade typer för heltal, flyttal, tecken och boolska värden. Tabell 5.1 listar de vanligaste av dessa och hur stora de är i antal bitar.

Tabell 5.1:De vanligaste primitiva typerna i de tre språken (antal bitar).

Visual C++

C#

VB.NET

.NET FCL

int/long (32) int (32) Integer (32) System.Int32 (32) __int64 (64) long (64) Long (64) System.Int64 (64) short (16) short (16) Short (16) System.Int16 (16) char (8) byte (8) Byte (8) System.Byte (8) wchar_t (16) char (16) Char (16) System.Char (16) float (32) float (32) Single (32) System.Single (32) double (64) double (64) Double (64) System.Double (64) bool (8) bool (8) Boolean (8) System.Boolean (8)

Här syns både skillnader och likheter. En long i Visual C++ är bara 32 bitar och för 64-bitars heltal används istället __int64 (som inte är standard-C++). (Observera att storlekssiffrorna för C++ gäller specifikt för Visual C++ (version 7.1/VS.NET 2003); i standard-C++ är inte storleken exakt definierad.) Datatypen char är 16 bitar i C# och VB.NET, vilket hänger samman med att all teckenhantering sker med Unicode-tecken.1

Tabellens fjärde kolumn listar också typernas namn i .NET-ramverket. C#:s och VB:s typer är bara smidigare sätt att komma åt dessa. Om man vill går det lika bra att använda .NET-namnen, vilket föredras i en del litteratur, t ex [5].

1Unicode kan användas även i C++, om datatypen char undviks. Typen wchar_t kan användas istället,

alternativt Windowstypen _TCHAR (som används av MFC). Den senare kan vara antingen 8 eller 16 bitar beroende på en inställning. Liknande gäller för strängar. Av läsbarhetsskäl används inte Unicode i C++ i denna rapport.

References

Related documents

Dock kan vissa av dessa egenskaper se olika ut syntaxmässigt. Som tidigare nämnt ärver alla klasser av Object. Eaddy menar att System.Object är en kopia av

Efter analys av bek¨ ampningsmetodernas anv¨ andbarhet framtr¨ adde restriktionsytor, d¨ ar kemisk bek¨ ampning inte ¨ ar till˚ aten, och driftplatser, d¨ ar bek¨ ampningen

This is the largest category of SMEs in the recommendation, if a company exceed these requirements it is seen as a large company and has to report according to all the

Maskinkod är helt obegripligt för den oinvigde: till exempel betyder 1000101111000011 ”flytta data från b till a” för en Pentium-kompatibel CPU; fullkomligt meningslöst

för att hämta medlemsvariabler från ett vanligt objekt, medan operatorn -&gt; används för att hämta medlemsvariabler från en pekare till ett objekt. Efter operatorn skriver

Our findings suggest that in the group of students, four significant ways of knowing the landscape of juggling seemed to be important: grasping a pattern; grasping a rhythm; preparing

(Undantag finns dock: Tage A urell vill räkna Kinck som »nordisk novellkonsts ypperste».) För svenska läsare är Beyers monografi emellertid inte enbart

DIABETES ’ VET OCH VINN-tävling rullar vidare med nya knepiga kuggfrågor. Många läsare tycks ha haft vissa problem med förra numrets omgång, för vi lyckades bara vaska