Viele Leute benutzen Visual Studio. Viele nutzen es aber nur oberflächlich. Diese Tipsammlung soll einige Kniffe aufzeigen, die einen professioneller und schneller arbeiten lassen. VStudio enthällt nämlich eine Reihe von mehr oder weniger versteckten Bonbons, die es zu nutzen gilt:
Visual Studio (Vstudio) ist ein durchaus sehr gutes und universelles Werkzeug für die C/C++Programmierung. Es wurde ja schließlich ursprünglich von einer englischen Firma entwickelt -- im Auftrag von Microsoft. Ist also mal wieder keine MS-Entwicklung. Manch vim- oder emacs-Fan wird wohl kein gutes Haar dranlassen und unzulänglichkeiten des Editors sind bestimmt da, doch will ich mich hier mal um die positiven Eigenschaften der IDE kümmern. In Vstudio sind nämlich einige praktische Kleinigkeiten versteckt, die das Entwicklerleben vereinfachen. Wie immer sind die meißten dieser Kleinigkeiten mit etwas Arbeit verbunden. Man muss also erst etwas investieren um dannach zu profitieren. In der Regel lohnt der Aufwand.
Konkret habe ich die folgenden Tips:
Pseudoregister
Bedingte Haltepunkte
Drag & Drop bei Variablennamen
Die Suchen/Ersetzen-Funktion des Editors kann Reguläre Ausdrücke verarbeiten. Reguläre Ausdrücke sind ein recht universelles und vom Aufwand/Nutzen-Verhältnis sehr effizientes Werkzeug. Man kann Reguläre Ausdrücke häufiger einsetzen als man glaubt. Ich möchte den Leser auch dazu ermuntern sich mal 5min. für einen durchschnittlichen Ausdruck zeit zu nehmen um dann im Anschluß mit einem Klick 60 Zeilen zu korrigieren. Nur zu oft ist es ja so, dass man sich sagt: "Aja, die paar Zeilen...das geht doch schneller per Hand". Schuld daran ist die Denkfaulheit. Also wider dem Schweinehund.
Doch nun zum VStudio. Bei der Maschine scheint es sich um eine modifizierte Emacs-Maschine zu handeln. Ich mache das daran fest, dass z.B. die Klammern einen Backslash davor stehen haben und weil bei Microsoft sowiso alles geklaut ist... Microsoft hat in die Reguläre Ausdrücke-Maschine einige nette Erweiterungen/Kurzschreibweisen eingebaut, wie zum Beispiel C++-Bezeichner. Der Ersetzen-Dialog ist durchaus kompfortabel geraten, denn fast alles was die Reguläre Ausdrücke-Maschine in den Eingabefeldern verträgt ist über die kleinen Dreieckspfeile daneben zu erreichen. Da dies hier kein Kurs für Reguläre Ausdrücke werden soll beschränke ich mich hier auf eine Auflistung der Metazeichen und ein illustratives Beispiel.
abcABC | Das Zeichen an sich |
^ | Zeilenanfang |
. | Beliebiges Zeichen |
[] | Zeichenklasse |
[^] | negierte Zeichenklasse |
\(\) | Zeichen Selektieren (kann mit \1..\9 drauf zugreifen) |
\~ | Ausdruck negieren |
\! | Oder |
+ | 1 oder n-Mal |
* | 0 oder n-Mal |
\{\} | Gruppierung, wohl nichteinfangende Klammern |
\:b | Leerzeichen |
\:a | Alphanumerisches Zeichen |
\:c | Zeichen |
\:d | Ziffer |
\:h | Hexziffer |
\:n | Nummer |
\:z | Ganzzahl also \:d+ |
\:i | C++-Bezeichner |
\:w | Wort also \:a+ |
\:q | Wort in Anführungszeichen |
\ | Entwertungszeichen für \\ \' \" \* \. \[ usw. |
$ | Zeilenende |
So ganz im Klaren darüber wie man damit umgeht bin ich mir selbst nicht, da es sich hierbei um eine unübliche Reguläre Sprache handelt. Bei den Gruppen scheint es sich nicht um die sich üblicherweise dahinter verbergende Wiederholung n-m Mal zu handeln , sondern um die von Perl bekannten nichteinfangende Klammern. Auch bei dem bisher unbekannten Nicht scheint die Maschine etwas inkonsistent zu arbeiten. Immerhin, es gibt Reguläre Ausdrücke und die Kammern fangen auch ein, so dass man die eingefangenen Teilzeichenketten beim Ersetzen mit \1,\2 ... verwenden kann.
Oft hat man das Problem, dass man eine komplexe Datenstruktur überwachen will während man durch das Programm hindurchwartet. In der Regel sind die Datenstrukturen aber zu umfangreich und zu unhandlich um sie in die Watch aufzunehmen bzw. sie erfordern ein ewiges gescrolle usw.
Für solche Fälle haben die VStudio-Entwickler selbstdefinierte Watches vorgesehen. In der Datei ??? mit der Syntax ??? kann man sie selbst definieren........ FIXME
Noch nie gehört? Ist vielleicht auch ein komischer Name. Aber was dahintersteckt hat durchaus praktischen Wert. Im Prinzip sind Pseudoregister die Rückgabewerte von Funktionsaufrufen, die irgendwie im Hintergrund geschehen. Ganz so universell sind sie alerdings doch nicht. Es sind nur Speicheradressen oder echte Register möglich. Doch das ist eigentlich irrelevant, da es so oder so eine vorgegebene Liste von Registern gibt. Die kann man nutzen oder auch nicht.
Das bekannteste Pseudoregister ist das @ERR-Pseudoregister. Es enthällt den Wert, des
letzten Fehlers. Es zeigt also genau das an, was ein Aufruf von GetLastError();
auch liefern würde. Da der Letzte Fehlerkode ein Feld im TEB (Thread Environment Block) ist,
handelt es sich um einen einfachen Speicherzugriff und ist daher mit einem Pseudoregister problemlos
zu bewerkstelligen.
Bez. | Bedeutung |
---|---|
@ERR | Wert des letzten Fehlers; dasselbe was auch GetLastError() liefert. |
@ERR,hr | Zeigt den letzten Fehler in textueller Form an. Schickt ihn also durch FormatError(). |
@TIB | Beginn des TIB (Thread Information Block). Damit und mit + kann man beliebige Felder des TIB in die Watch aufnehmen. |
@CLK | Undokumentiertes Clock-Register. Funktioniert nur in der Watch. |
@EAX, @EBX, @ECX, @EDX, @ESI, @EDI, @EIP, @ESP, @EBP, @EFL | x86-Registersatz. |
@CS, @DS, @ES, @SS, @FS, @GS | x86-Segmentregister. |
@ST0, @ST1, @ST2, @ST3, @ST4, @ST5, @ST6, @ST7 | x86-Fließkommaregister. |
Das Beste jedoch zum Schluß: Man kann Pseudoregister als Operanden in bedingten Haltepunkten Verwenden. Das eröffnet völlig neue Debuggingmöglichkeiten. Man lässt einen bedingten Haltepunkt mitlaufen, der sich meldet sobald eine win32-Funktion fehl schlägt.
Haltepunkte an sich sind schon mal ein herforagendes Mittel um den eigenen Denkfehlern ein Schnippchen zu schlagen. Doch hat man nur zu oft die Situation, dass man x Schleifendurchläufe benötigt, ehe es relevant wird im Singlestepmodus das Programm zu untersuchen. Oder irgendwie irgendwo ändert sich eine Variable obwohl sie das nicht dürfte. Genau für solche Fälle sind bedingte Haltepunkte das richtige. Man richtet sie ähnlich ein wie FIXME und Pseudoregister kann man in dieses eingabefeld auch ineinstecken.
Der Debugger wie man ihn gemeinhin im VStudio kennt ist ein sogenannter Hostdebugger, weil er auf demselben Rechner (Host) läuft, wie das Programm. Das geht auch in fast allen Fällen gut und aus der Sicht des Betriebsystems dank Speichertrennung sogar in 100% der Fälle. Der Knackpunkt ist das GUI. Da ein ein zu debuggendes GUI-Programm die gleiche Schnittstelle wie der Debugger verwendet, und diese nur einen einzigen Fokus besitzt, kommen sich die beiden mehr oder weniger ins Gehege. Jeder GUI-Programmierer kennt das: Man möchte per Haltepunkt ein Stück GUI-Programmkode untersuchen und muss das passende Ereignis auslösen. Doch noch ehe man soweit ist, spricht der Debugger an und macht mit seinem GUI alles zunichte.
Für so etwas eignet sich ein Remote Debugger recht gut. Da er auf einem anderen Rechner arbeitet hat er seinen eigenen GUI-Fokus und kann er dem debuggten Programm nicht mit seinem GUI dazwischenfunkten. Nachteilig an dieser Methode ist allerdings, dass man zwei Rechner benötigt. Natürlich kann man dergleichen auch mit Bochs oder VMWare realisieren. Hat aber den Nachteil, dass beide "Rechner" virtuelle Maschinen sein müssen und daher entweder das Entwickeln langsam wird oder ein Organisationsoverhead dazukommt. Sehen wir uns nun an, wie man so eine Umgebung einrichtet:
Ich werde hier vom Zwei-Rechner-Ansatz ausgehen. Man hat dort eine Entwickler- und Testmaschnine und einen Rechner zur Steuerung des Debuggers. Der Entwiklerrechner bleibt so wie er ist. Das zu untersuchende Programm wird auf dem Entwicklerrechner ausgeführt. Nun benötigt man eine Steuerungssoftware für den Debugger. Hierzu eignet sich der jedem SDK beiliegende Windbg. KONKRETER FIXME
Drag & Drop ist ein wichtiges Bedienelement im VStudio. Man sollte eher einmal mehr als einmal zu wenig versuchen, ob sich etwas mit Ziehen und Ablegen erreichen lässt. Einige Beispiele was geht sind hier aufgelistet: