Programmieren in C++ Prof. Dr. C. Stamm, Prof. Horst Veitschegger Tutorial Visual Studio Lernziele Sie können Visual Studio bedienen und für C++-Projekte gezielt einsetzen. Sie kennen das Konzept der Applikations-Templates und wissen es anzuwenden. Sie sind in der Lage, eine erste Konsolenanwendung zu generieren, kompilieren, binden und auszuführen. Sie verstehen das Konzept der Konfigurationen und Plattformen und wissen, wo die wichtigsten Einstellungen zum Projekt, Compiler und Linker gemacht werden können. Sie können den Debugger bedienen und sinnvoll nutzen. Sie haben Zugriff auf das umfassende Hilfsangebot von MSDN und können MSDN über Index, Suche und kontextsensitiv ansprechen. 1 Visual Studio C++ Microsoft Visual Studio (VS) gehört zu den bekanntesten Entwicklungsumgebungen unter Windows. Zur komfortablen Programmierumgebung gehört ein integrierter Compiler und Linker, welcher auch über die Konsole gestartet werden kann. Im vorliegenden Tutorial verwenden wir die englische Version Premium 2012. Wir empfehlen die neuste Version von Visual Studio für den Unterricht, weil viele der neuen C++11 Sprachkonstrukte erst ab Version 2012 verfügbar sind. Sollten Sie bisher noch nie mit Visual Studio gearbeitet haben, so achten Sie bitte darauf, dass bei der ersten Verwendung die C++ spezifischen Editor-Einstellungen verwendet werden. Nach dem Aufstarten sollten Sie ein Bild ähnlich zu dem rechts sehen. Die einzelnen Menüpunkte enthalten alle Befehle, die Sie verwenden werden und natürlich noch viel mehr. Eine effiziente und professionelle Arbeit wird jedoch erst möglich sein, wenn Sie die wichtigsten Befehle über die Toolbars oder noch besser über die entsprechenden Shortcuts direkt ansteuern können. Dies gilt vor allem für das Kompilieren, Starten und Debuggen. Stellen Sie zuerst sicher, dass die Toolbars „Build“ und „Text Editor“ über das Menü „VIEW/Toolbars“ eingeschaltet sind. 1 2 Applikations-Templates Eine entscheidende Qualität von VS sind die bereits vorhandenen Applikationsschablonen (Templates), welche üblicherweise in Form von Wizards vorhanden sind. Für die verschiedensten Typen von Anwendungen (Konsole, GUI, Mobile usw.) stehen einfach zu bedienende Dialogfolgen zur Verfügung, welche der Benutzerin ermöglichen, mit wenigen Mausklicks eine individuelle, lauffähige Basisanwendung zu erstellen. Unter „FILE/New/Project“ erhalten Sie eine grosse Auswahl der bestehenden Templates. Folgende C++-Templates sollten Sie sehen: Im linken Teil des Dialogs finden Sie die verschiedenen Projekttypen hierarchisch geordnet. Wir interessieren uns hier vor allem für die verschiedenen C++-Projekttypen: ATL (Active Template Library): “The Active Template Library (ATL) is a set of template-based C++ classes that let you create small, fast Component Object Model (COM) objects. It has special support for key COM features, including stock implementations, dual interfaces, standard COM enumerator interfaces, connection points, tear-off interfaces, and ActiveX controls”. CLR (Common Language Runtime): Applikationen, welche auf dem .NET-Framework basieren und das CLR verwenden. General: Benutzerdefinierte Wizards, leeres Projekt und Makefile-Projekt. MFC (Microsoft Foundation Classes): MFC ist eine umfangreiche Klassenbibliothek zur Entwicklung von Microsoft Windows Anwendungen. MFC enthält eine grosse Vielzahl von verschiedenen Fensterklassen, Dialogen, Betriebssystem spezifische Unterstützung, Datenstrukturen (Strings, Arrays, Listen, Maps usw.) Test: Ein Test-Projekt erlaubt die Erstellung von Unit-Tests. Win32: Mit Win32-Projekten sind Konsolenanwendungen, statische und dynamische Bibliotheken (Libraries, DLLs) für die Windows 32-Bit-Plattform gemeint. Solche Projekte können zusätzlich ATL- oder MFC-Unterstützung enthalten. Vertiefung Schauen Sie alle anderen Projekttypen auch in den anderen Programmiersprachen durch und gewinnen Sie dadurch einen Eindruck von der Vielzahl von verschiedenen Basisanwendungen, die auf Knopfdruck generiert werden können. 2 3 Hallo C++ Wie üblich bei der C/C++-Programmierung beginnen wir hier mit einer „Hello, world!“ Variante. Mit diesem kleinen Testprogramm soll sichergestellt werden, dass die einzelnen Teilschritte der Entwicklungskette (Quellcode schreiben, kompilieren, binden, ausführen) aufeinander abgestimmt sind und funktionieren. Zudem zeigt dieses Testprogramm auch, wie Textausgaben auf der Konsole gemacht werden. So gehen Sie vor Starten Sie Visual Studio (VS) und wählen Sie den Menüpunkt „FILE/New/Project…“ aus. Wählen Sie in diesem Dialog auf der linken Seite „Visual C++/Win32“ als Projekttyp und rechts „Win32 Console Application“ aus. Im unteren Teil des Dialogs können Sie Angaben zum Projektnamen, zum Beispiel „HelloC++“, und allenfalls zum Namen der Solution machen. Im nächsten Dialog wählen Sie auf der linken Seite „Application Settings“ und schauen sich auf der rechten Seite die möglichen Einstellungen an. Wählen Sie die Konsolen-Applikation ohne vorkompilierter Header-Dateien und ohne „Security Development Lifecycle (SDL) checks“ aus. Schliessen Sie den Dialog mit „Finish“ ab. Im „Solution Explorer“ (linkes Fenster) finden Sie neben den erzeugten Quellcode-Dateien auch eine Datei mit dem Namen „ReadMe.txt“. Lesen Sie die als erstes, um sich einen Überblick über die erstellten Dateien zu verschaffen. Bevor Sie irgendwelche Veränderungen an den Einstellungen oder Quellcode-Dateien vornehmen, ist es immer sinnvoll, das neu erzeugte Projekt gleich zu testen. Wählen Sie dazu „Start Without Debugging“ im Menü „Debug“ oder Ctrl-F5. Ihre ausführbare Datei wird automatisch erstellt und innerhalb eines neuen Kommandofensters ausgeführt. Hintergrund VS legt standardmässig alle Projekte in einen Unterordner von „Visual Studio 2012“ ab. In VS wird zudem zwischen Solutions und Projects unterschieden: ein Projekt ist eine Ansammlung von Dateien, die zusammengenommen zum Beispiel zu einem ausführbaren Programm (*.exe), zu einer statischen Bibliothek (*.lib) oder zu einer dynamisch gebundenen Bibliothek (*.dll) gehören. Eine Solution kann mehrere Projekte beinhalten, die voneinander abhängen dürfen. Sie kann somit als Menge von Projekten betrachtet werden und dient daher vor allem der Projektorganisation. Oft enthält eine Solution zum Beispiel ein Applikationsprojekt, mehrere Testprojekte und ein DeploymentProjekt. Je nachdem, ob eine Solution mehrere Projekte beinhalten soll oder nicht, macht es Sinn, für die Solution ein eigenes Verzeichnis und für alle Teilprojekte je ein Unterverzeichnis zu verwenden. Drei Gruppen von möglichen Optionen stehen zur Auswahl. Die erste Gruppe „Application type“ ist die wichtigste. Hier entscheidet sich, ob Sie eine Applikation mit Fenstern („Windows application“), eine Konsolenapplikation oder eine Bibliothek erstellen wollen. Die Gruppe „Additional options“ ermöglicht entweder die alleinige Erzeugung von Projektdateien (ohne dass Quellcode-Dateien erstellt werden) oder die Verwendung von vorkompilierten Header-Dateien (vor allem sinnvoll bei grösseren Projekten, die Bibliotheken mit umfangreichen Header-Dateien verwenden). In der dritten Gruppe kann schliesslich angegeben werden, ob eine oder mehrere der aufgelisteten Bibliotheken (ATL, MFC) verwendet werden soll. Der Wizard erzeugt nun ein Projektverzeichnis mit dem von Ihnen vorgegebenen Namen und legt eine ganze Menge von Dateien an. Ein Teil der Dateien enthalten die Projekteinstellungen und ein anderer Teil den Quellcode. VS stellt nun fest, dass noch keine (aktuelle) ausführbare Datei für Ihr Projekt vorhanden ist. Daher wird der Compiler gestartet und alle cpp-Dateien werden in der richtigen Reihenfolge kompiliert. Im Projektordner auf der Festplatte finden Sie nun einen Unterordner „Debug“, welcher unter anderem die kompilierten Objektdateien (*.obj) enthält. Nach dem Compiler wird der Linker aufgerufen, welcher die Objektdateien und zusätzliche, notwendige Bibliotheken zu einer ausführbaren Datei (*.exe) bindet. Aus der Dateigrösse Ihrer ausführbaren Datei können Sie herauslesen, dass mehr als nur die Objektdateien darin enthalten sind. Wenn Sie die Konsolenanwendung aus VS heraus starten, wird jedes Mal ein neues Kommandofenster geöffnet. Selbstverständlich können Sie Ihre Konsolenanwendung aber auch direkt aus dem Projektordner auf der Festplatte oder mithilfe eines selbst geöffneten Kommandofensters starten. 3 Bis jetzt hat Ihr Programm keinerlei Funktionalität. Das wollen wir nun ändern. Öffnen Sie dazu das Hauptprogramm „HelloC++.cpp“ im Editor und ergänzen Sie es wie nebenstehend gezeigt. Führen Sie anschliessend das veränderte Programm innerhalb von VS aus. Sie sehen, nur noch „HelloC++.cpp“ wird neu kompiliert. Fahren Sie mit dem Cursor zuerst über _tmain und anschliessend über _TCHAR*, dann sehen Sie im grau aufleuchtenden Text, welche Definitionen hinter diesen Bezeichnern stehen. Wir wollen später die Projekteinstellungen so abändern, dass anstatt wmain() die „normale“ main()-Methode aufgerufen wird. std::cout ist das Standard-Output-Stream-Objekt, welche die formatierten Ausgabe auf der Konsole ermöglicht. Es ist Teil der C++-Standardbibliothek und wird über die entsprechende Header-Datei ins Projekt eingebunden (#include <iostream>). Der Linksschiebe-Operator << hat im Zusammenhang mit Stream-Objekten die Bedeutung, dass der String „Hello, World!“ auf die Konsole ausgegeben wird. In C++ ist es normal, die Operatoren mit speziellen Funktionalitäten zu überladen. Auch in C++ beginnt das Programm in der main()-Funktion, welche als Parameter die Argumente beim Programmaufruf erhält und einen Fehlercode (0 = kein Fehler) zurückliefert. Die von VS erstellte main()-Funktion hat einen leicht veränderten Namen _tmain. Das Präfix „_t“ symbolisiert einen Platzhalter, welcher noch vor der eigentlichen Kompilation durch den Präprozessor ersetzt wird. Dieser Platzhalter wird verwendet, weil es für die Konsolenapplikation zwei unterschiedliche MainMethoden gibt, je nachdem ob die Kommandozeilenparameter vom Typ char* oder wchar_t* sein sollen. 4 Projekteinstellungen Nun geht es darum, dass Sie die Entwicklungsumgebung VS besser kennen lernen und einen ersten Eindruck von den vorhandenen Möglichkeiten mitnehmen. Auf den Programmcode-Editor von VS wollen wir hier nicht näher eingehen, weil Sie bereits genügend Erfahrung mit solchen Editoren mitbringen. Worauf wir jedoch unser Augenmerk legen wollen, ist der Build-Prozess bestehend aus Kompilation und Bindung (Linking). Bei der zuvor automatisch generierten Anwendung sind auch alle notwendigen Projekteinstellungen vorgenommen worden, um einen reibungslosen Build-Prozess zu ermöglichen. Nicht immer ist man in dieser komfortablen Situation, dass bereits alle Projekteinstellungen passend sind. Daher ist es sehr wichtig, schon früh einen Blick in diese Einstellungen zu werfen, um sich mit den vorhandenen Optionen vertraut zu machen. Bevor wir dies tun, sollten wir nochmals einen Blick auf die Projektorganisation werfen. Sie haben an früherer Stelle gelernt, dass eine Solution mehrere Projekte enthalten kann. Nun kommt hinzu, dass ein Projekt mehrere Konfigurationen und mehrere Zielplattformen besitzen darf. Mit Konfigurationen sind typischerweise die zwei Ausprägungen „Debug“ und „Release“ gemeint. Für jede einzelne Kombination aus Konfiguration und Zielplattform können nun individuelle Projekteinstellungen definiert werden. Für eine Entwicklungsversion (Debug-Version) unter Win32 sind eben andere Projekteinstellungen notwendig, als zum Beispiel für eine produktive Version (ReleaseVersion) unter x64. Die standardmässig gewählte Konfiguration und Plattform sehen Sie in der folgenden Abbildung hervorgehoben. 4 Schauen wir uns nun also die Projekteinstellungen für die Debug-Version der Win32- bzw. x64Plattform an. Um diese Einstellungen einsehen zu können, wählen Sie entweder im Menü „PROJECT/Properties“ oder klicken Sie mit der rechten Maustaste auf das Projekt im „Solution Explorer“ und wählen Sie dann „Properties“ aus. Sie werden den nachfolgenden Dialog erhalten. Wir haben bewusst die Teilbäume C/C++ und Linker geöffnet, damit Sie einen ersten Eindruck von der Fülle der möglichen Einstellungen erhalten. Selbstverständlich werden wir Sie damit verschonen, all diese Einstellungen hier zu erläutern. Vielmehr geht es darum, auf ein paar zentrale Punkte hinzuweisen. Im nebenstehenden Dialog sehen Sie die generellen Einstellungen. Einstellungen die fett hervorgehoben sind, entsprechen nicht den Standardeinstellungen und wurden in unserem Fall bereits durch den Wizard vorgenommen. Rechts oben finden Sie den Zugang zur kontextsensitiven Hilfe. Output Directory: Das Verzeichnis für die resultierende Programmdatei wird hier zwei Makros $(SolutionDir) und $(ConfigurationName) gebildet. Das erste Makro bezeichnet das von Ihnen bezeichnete Verzeichnis für die Solution und das zweite Makro ist ein Platzhalter für den Konfigurationsnamen, im aktuellen Fall also für Debug. Intermediate Directory: Das Verzeichnis für die vom Compiler und anderen Tools generierten Dateien, z.B. die Objektdateien. Use of MFC und Use of ATL: Je nachdem, ob Sie im Wizard die Verwendung von ATL bzw. MFC angewählt haben, sehen Sie hier die Verwendung dieser Klassenbibliotheken. Bei Ihrer Konsolenanwendung sollte „Use Standard Windows Libraries“ und „Not Using ATL“ stehen. Character Set: VS kann mit verschiedenen Zeichensätzen umgehen, d.h. der generische Typ TCHAR wird mit char oder wchar_t ersetzt. Entsprechendes gilt für Zeichenketten (Strings). Davon sind aber nicht nur die Datentypen selber betroffen, sondern auch alle Methoden mit Parameterlisten, welche Zeichen oder Zeichenketten verwenden. Gut programmierte Applikationen können dann sowohl mit Unicode als auch mit ASCII-Code als Zeichensatz fehlerfrei kompiliert werden. Ändern Sie nun den verwendeten Zeichensatz Ihrer Konsolenanwendung von Unicode auf „Use Multi-Byte Character Set“, was einer Anwendung des ASCII-Codes bzw. UTF-8 gleichkommt. Übernehmen Sie die Änderungen und überprüfen Sie erneut die Platzhalter im Programmtext. Sie sollten nun sehen, dass _tmain durch main ersetzt wird. Compiler Einstellungen Im Teilbaum „C/C++“ finden Sie die notwendigen Einstellungen, welche mit der Kompilierung zusammenhängen. Verwenden Sie die kontextsensitive Hilfe, um sich über die folgenden Einstellungspunkte im MSDN näher zu informieren: General/Additional Include Directories Preprocessor/Preprocessor Definitions Code Generation/Enable C++ Exceptions Code Generation/Runtime Library Code Generation/Struct Member Alignment Language/Enable Run-Time Type Information Precompiled Headers/Precompiled Header Linker Einstellungen Im Teilbaum „Linker“ finden Sie schliesslich alle notwendigen Einstellungen im Zusammenhang mit dem Binder (Linker). Verwenden Sie wiederum die kontextsensitive Hilfe: General/Additional Library Directories Input/Additional Dependencies Advanced/Target Machine 5 Nun sollten Sie einen ersten guten Überblick über die Vielfalt der möglichen Einstellungen gewonnen haben. Zu diesem Zeitpunkt ist nicht wichtig, dass Sie alle Einstellungen bis ins letzte Detail verstanden haben. Vielmehr geht es darum, dass Sie bei Problemen mit dem Compiler oder Linker eine Idee haben, wo Sie nachsehen müssen, um diese Probleme lösen zu können. Vertiefungen Vergleichen Sie die Einstellungen der Release- mit der Debug-Version und rapportieren Sie diese Unterschiede. 5 Debugger In einer Programmiersprache wie C++ mit Zugriff auf die Adressen der Variablen ist ein gut funktionierender Debugger ein enorm wichtiges Werkzeug, weit mehr als in Java beispielsweise. Für die Benutzer ist vor allem die einfache Bedienbarkeit, die Flexibilität und Mächtigkeit eines vorhandenen Debuggers wichtig. Der Debugger von VS kann in diesen Bereichen sehr gut punkten. In der nachfolgenden Abbildung sehen Sie unser ursprüngliches Hello-World-Programm um ein paar Zeilen erweitert. In den zusätzlichen Zeilen werden die Programm-Argumente, welche vom Aufrufer an main(…) übergeben worden sind auf der Konsole ausgegeben. Wie Sie bereits erfahren haben, werden standardmässig zwei Konfigurationen pro Projekt angeboten: eine Debug- und eine Release-Version. An der Position (#1) können Sie einfach zwischen den verschiedenen Konfigurationen wechseln. Während die Debug-Version vor allem zur Entwicklung des Programms dient, so ist die Release-Version primär als optimierte Version für den Einsatz des Programms gedacht. Die Release-Version ist deutlich schlanker, da sie keinen Debug-Code enthält, und infolge der Optimierungen um ein Vielfaches schneller als die Debug-Version ist. In der DebugKonfiguration können Sie Ihr Programm wahlweise mit oder ohne Debugger starten. Üblicherweise benutzen Sie die Funktionstaste F5, um das Programm mit dem Debugger zu starten. Sobald Sie sich im Debug-Modus befinden, wechselt die Statuszeile ihre Farbe auf orange. An der Position (#2) können Sie den Debugger pausieren, stoppen oder erneut starten. Im Menü „DEBUG“ sehen Sie zudem die wichtigsten Funktionen des Debuggers auf einen Blick. Es ist ratsam, die meistgebrauch1 ten Funktionstasten zur Steuerung des Debuggers (F9-F11) sich einzuprägen. An der Position (#3) ist mit F9 ein Breakpoint auf der entsprechenden Programmzeile platziert worden. Der Breakpoint wird als roter Punkt dargestellt. Da sich das pausierte Programm gerade auf der gleichen Zeile befindet, ist der rote Punkt von einem gelben Pfeil überlagert, welcher die aktuelle Debugger-Position markiert. Unterhalb des Quellcode-Fensters sehen Sie an der Position (#4) die verschiedenen Debugger-Fenster (Autos, Locals, …, Watch1) und daneben an der Position (#5) den Call-Stack. In „Autos“ zeigt Ihnen der Debugger die wichtigsten Variablen an der aktuellen DebuggerPosition. Damit können Sie in den meisten Fällen auf das eigenständige Festlegen der zu inspizierenden Variablen verzichten, wie es in Watch1 möglich wäre. #1 #2 #3 #5 #4 1 Sollten Sie sich bereits an die Eclipse-Tastenbelegung gewöhnt haben, so können Sie VS problemlos unter „TOOLS/Customize“ Ihren Bedürfnissen anpassen. 6 6 MSDN Das Microsoft Developer Network (MSDN) ist das zentrale Nachschlagewerk für fast alle Belange eines Windows-Programmierers. Dazu gehört natürlich auch ein C++ Referenz-Manual. Das MSDN kann lokal auf dem Rechner installiert oder über das Internet verwendet werden (msdn.microsoft.com). Unter „HELP/Set Help Preference“ können Sie wählen, ob die Hilfe im Browser oder wie unten gezeigt im speziellen Help-Viewer dargestellt wird. Im Reiter „Manage Content“ können Sie steuern, welche Inhalte auf Ihrem Rechner lokal verfügbar sein sollen. Für Sie ist vor allem die Dokumentation „Visual C++“ von Interesse. Wählen Sie daher diese Dokumentation aus und aktualisieren die lokale Dokumentation mit „Update“. Nach erfolgter Aktualisierung finden Sie auf der linken Seite den Eintrag „Visual C++“ unterhalb von „Visual Studio 2012“. Versuchen Sie nun, sich über das Schlüsselwort „auto“ von C++ zu informieren. In der nächsten Abbildung sehen Sie auf der linken Seite, wo die Informationen über „auto“ zu finden sind. Auf der rechten Seite finden Sie dann die entsprechende Information. 7 In der Abbildung sind zwei wichtige Bereiche/Funktionen hervorgehoben: Das Auffinden eines passenden Artikels zum gewünschten Thema erfolgt entweder über den Index oder über die Suche. Findet man über den Index den gewünschten Artikel nicht, so hilft auf alle Fälle die Suche. Nach einer erfolgreichen Suche eines Artikels ist es oft notwendig, ähnliche oder weiterführende Informationen zu erhalten. Hier bietet es sich an, den Inhaltsbaum der linken Seite mit dem im Hauptfenster angezeigten Artikel zu synchronisieren, so dass ersichtlich wird, an welcher Stelle der aktuelle Artikel im hierarchischen Inhaltsbaum abgelegt wurde. Auf diese Weise können weiterführende oder übergeordnete Informationen anschliessend direkt über den Inhaltsbaum angewählt werden. Die Synchronisation erfolgt über den links oben markierten Knopf. 8