Ausdrücke in systemeigenem C++
Der Debugger akzeptiert die meisten Microsoft und die Ausdrücke ANSIs C/C++.Der Debugger bietet auch systeminterne Funktionen und Kontextoperatoren bereit, um sicherer und benutzerfreundlicher zu machen, Ausdrücke auszuwerten.In diesem Thema werden auch die Einschränkungen für C++-Ausdrücken, die Folgendes beachten müssen:
Kontextoperatoren und die meisten Formatbezeichner können nicht in Code oder in Skript- bzw. verwalteten Codeausdrücken verwendet werden.Sie sind spezifisch für die systemeigene C++-Ausdrucksauswertung.
In diesem Abschnitt
Verwenden der intrinisic Funktionen des Debuggers, um den Zustand beibehalten
Verwenden der Kontextoperatoren, um eines Symbols anzugeben
Einschränkungen für systemeigene C++-Ausdrücken
Zugriffssteuerung
Mehrdeutige Verweise
Anonyme Namespaces
Konstruktoren, Destruktoren und Konvertierungen
Vererbung
Inline und systeminterne Funktionen
Numerische Konstanten
Operatorfunktionen
Überladen
Rangfolge
Symbolformate
Typumwandlung
Verwenden der intrinisic Funktionen des Debuggers, um den Zustand beibehalten
Die Debuggersysteminternen funktionen geben Ihnen die Möglichkeit, bestimmte C/C++-Funktionen in Ausdrücken aufzurufen, ohne den Zustand der Anwendung zu ändern.
Debuggersysteminterne funktionen:
Werden garantiert, um sicherzustellen: eine Debuggersysteminterne funktion ausführen, beschädigt nicht den Prozess, der gedebuggt wird.
Werden in allen Ausdrücken, sogar in Szenarien zulässig, in denen Nebeneffekte und Funktionsauswertung nicht zulässig sind.
Arbeiten Sie in Szenarien, in denen die regulären Funktionsaufrufe nicht möglich sind, wie Debuggen eines Minidumps.
Debuggersysteminterne funktionen können bequemer ausführen, Ausdrücke auszuwerten.Beispielsweise ist strncmp(str, "asd") viel einfacher, in Haltepunktbedingung als str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’ zu schreiben.)
Bereich |
Systeminterne Funktionen |
---|---|
Zeichenfolgenlänge |
strlen, wcslen, strnlen, wcsnlen |
Vergleich von Zeichenfolgen |
strcmp, wcscmp, stricmp, _stricmp, _strcmpi, wcsicmp, _wcscmpi, _wcsnicmp, strncmp, wcsncmp, strnicmp, wcsnicmp |
Suche nach einer Zeichenfolge |
strchr, wcschr, strstr, wcsstr |
Win32 |
GetLastError(), TlsGetValue() |
Windows 8 |
WindowsGetStringLen(), WindowsGetStringRawBuffer() Diese Funktionen erfordern den Prozess, der gedebuggt wird, auf Windows 8. ausgeführt werden.Das Debuggen von den Dumpdateien, die von einem Windows 8-Gerät erfordert generiert werden, auch, dass der Visual Studio-Computer. Windows 8 ausgeführt wird.Wenn Sie jedoch ein Windows 8-Gerät remote debuggen, kann der Visual Studio-Computer Windows 7. ausführen. |
Allgemeines |
__log2 Gibt die Protokollbasis 2 einer angegebenen Ganzzahl zurück, gerundet unteren zur nächsten ganzen Zahl. |
Verwenden der Kontextoperatoren, um eines Symbols anzugeben
Der Kontextoperator wird als zusätzlicher Operator vom systemeigenen Debugger bereitgestellt.Wenn Sie systemeigenen Code debuggen, können Sie den Kontextoperator verwenden, um eine Haltepunktposition, einen Variablennamen oder einen Ausdruck zu qualifizieren.Der Kontextoperator eignet sich z. B. insbesondere für die Angabe eines Namens außerhalb des Gültigkeitsbereichs, der andernfalls durch einen lokalen Namen verborgen würde.
Syntax
{,,[Modul] } Ausdruck
Modul ist der Name eines Moduls.Sie können einen vollständigen Pfad verwenden, um zwischen Modulen mit dem gleichen Namen zu herzustellen.
Ausdruck ist jeder gültige C++-Ausdruck, der zu einem gültigen Ziel, wie einem Funktionsnamen, einem Variablennamen oder einer Zeigeradresse in Modul aufgelöst.
Die geschweiften Klammern müssen zwei Kommas und der Name oder der vollständige Pfad enthalten des Moduls (ausführbare Datei oder DLL).
Beispielsweise einen Haltepunkt in der SomeFunction-Funktion von EXAMPLE.dll festlegen:
{,,EXAMPLE.dll}SomeFunction
Wenn der Modul Pfad ein Komma, ein eingebettetes Leerzeichen oder eine geschweifte Klammer enthält, müssen Sie Anführungszeichen um den Pfad verwenden, sodass der Kontextparser die Zeichenfolge ordnungsgemäß erkennen kann.Einfache Anführungszeichen werden als Teil eines Windows-Dateinamens betrachtet; daher sollten stets doppelte Anführungszeichen verwendet werden.Beispiel:
{,"a long, long, library name.dll", } g_Var
Wenn die Ausdrucksauswertung auf ein Symbol in einem Ausdruck trifft, wird in der folgenden Reihenfolge nach dem Symbol gesucht:
Beginnend mit dem aktuellen Block (in geschweifte Klammern eingeschlossene Anweisungen) vom lexikalischen Gültigkeitsbereich nach außen und weiter zum äußeren, umschließenden Block.Der aktuelle Block entspricht dem Code mit der aktuellen Position (Adresse des Anweisungszeigers).
Gültigkeitsbereich der Funktion.Die aktuelle Funktion.
Gültigkeitsbereich der Klasse, sofern sich die aktuelle Position innerhalb einer C++-Memberfunktion befindet.Der Klassengültigkeitsbereich umfasst alle Basisklassen.Von der Ausdrucksauswertung werden die normalen Dominanzregeln verwendet.
Globale Symbole im aktuellen Modul.
Öffentliche Symbole im aktuellen Programm.
Mit dem Kontextoperator geben Sie das beginnen Modul der Suche an umgehen und die aktuelle Position.
Einschränkungen für systemeigene C++-Ausdrücken
Bei der Eingabe eines C/C++-Ausdrucks in einem Debuggerfenster gelten die folgenden allgemeinen Einschränkungen:
Zugriffssteuerung
Der Debugger kann unabhängig von der Zugriffssteuerung auf alle Klassenmember zugreifen.Sie können beliebige Member eines Klassenobjekts, einschließlich Basisklassen und eingebetteten Memberobjekten, überprüfen.
Mehrdeutige Verweise
Wenn ein Debuggerausdruck auf einen mehrdeutigen Membernamen verweist, müssen Sie diesen mithilfe des Klassennamens kennzeichnen.Wenn CObject beispielsweise eine Instanz von CClass ist, die Memberfunktionen mit dem Namen expense sowohl von AClass als auch von BClass erbt, dann ist CObject.expense mehrdeutig.Sie können die Mehrdeutigkeit wie folgt auflösen:
CObject.BClass::expense
Um Mehrdeutigkeiten im Hinblick auf Membernamen aufzulösen, wendet die Ausdrucksauswertung normale Dominanzregeln an.
Anonyme Namespaces
Die systemeigene C++-Ausdrucksauswertung unterstützt keine anonymen Namespaces.Nehmen Sie z. B. an, Sie hätten folgenden Code:
#include "stdafx.h"
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
Hier besteht die einzige Möglichkeit, das Symbol test zu beobachten, in der Verwendung des ergänzten Namens:
(int*)?test@?A0xccd06570@mars@@3HA
Konstruktoren, Destruktoren und Konvertierungen
Es ist weder explizit noch implizit möglich, einen Konstruktor oder Destruktor für ein Objekt mittels eines Ausdrucks aufzurufen, durch den ein temporäres Objekt erstellt wird.Mit dem folgenden Ausdruck wird beispielsweise ein Konstruktor explizit aufgerufen, was eine Fehlermeldung zur Folge hat:
Date( 2, 3, 1985 )
Sie können keine Konvertierungsfunktion aufrufen, wenn es sich beim Ziel der Konvertierung um eine Klasse handelt.Eine solche Konvertierung impliziert die Erstellung eines Objekts.Wenn myFraction beispielsweise eine Instanz von CFraction ist, durch die der Konvertierungsfunktionsoperator FixedPoint definiert wird, verursacht der folgende Ausdruck einen Fehler:
(FixedPoint)myFraction
Ist das Ziel der Konvertierung jedoch ein integrierter Typ, kann eine Konvertierungsfunktion aufgerufen werden.Wenn durch CFraction eine operator float-Konvertierungsfunktion definiert wird, ist der folgende Ausdruck im Debugger zulässig:
(float)myFraction
Sie können Funktionen aufrufen, durch die ein Objekt zurückgegeben oder lokale Objekte deklariert werden.
Der Operator new oder der Operator delete kann nicht aufgerufen werden.Der folgende Ausdruck wird im Debugger nicht ausgeführt:
new Date(2,3,1985)
Vererbung
Wenn Sie den Debugger verwenden, um ein Klassenobjekt anzuzeigen, das über virtuelle Basisklassen verfügt, werden die Member der virtuellen Basisklasse für jeden Vererbungsweg angezeigt, obwohl nur eine Instanz dieser Member gespeichert wird.
Virtuelle Funktionsaufrufe werden von der Ausdrucksauswertung ordnungsgemäß behandelt.Angenommen, die CEmployee-Klasse definiert die virtuelle computePay-Funktion. Diese Funktion wird in einer Klasse, die von CEmployee erbt, neu definiert.Sie können computePay über einen Zeiger auf CEmployee aufrufen und so die geeignete Funktion ausführen lassen:
empPtr->computePay()
Sie können einen Zeiger auf ein abgeleitetes Klassenobjekt in einen Zeigertyp umwandeln, der auf ein Basisklassenobjekt zeigt.Sie können einen Zeiger auf ein Basisklassenobjekt in einen Zeiger auf ein Objekt umwandeln der abgeleiteten Klasse, außer wenn die Vererbung virtuell ist.
Inline und systeminterne Funktionen
Ein Debuggerausdruck kann Funktionen einer systeminterne Funktion des Compilers oder inline Funktion nicht aufrufen, es sei denn, dass die Funktion mindestens einmal als normale Funktion angezeigt wird.
Numerische Konstanten
Debuggerausdrücke können Ganzzahlkonstanten im Oktal-, Hexadezimal- oder Dezimalformat verwenden.Der Debugger erwartet standardmäßig Dezimalkonstanten.Diese Einstellung kann auf der Registerkarte Debuggen und dort auf der Seite Allgemein geändert werden.
Sie können Präfix- oder Suffixsymbole verwenden, um Zahlen in einem anderen Basisformat darzustellen.In der folgenden Tabelle sind die möglichen Formate aufgeführt.
Syntax |
Beispiel (dezimal 100) |
Basis |
---|---|---|
Ziffern |
100 oder 64 |
Dezimal oder hexadezimal, je nach der aktuellen Einstellung. |
0Ziffern |
0144 |
Oktalformat (Basis 8) |
0nZiffern |
0n100 |
Dezimalformat (Basis 10) |
0xZiffern |
0x64 |
Hexadezimalformat (Basis 16) |
Ziffernh |
64h |
Hexadezimalformat (Basis 16) |
Operatorfunktionen
Ein Debuggerausdruck kann Operatorfunktionen für eine Klasse implizit oder explizit aufrufen.Angenommen, myFraction und yourFraction sind Instanzen einer Klasse, durch die operator+ definiert wird.Die Summe der beiden Objekte kann mit folgendem Ausdruck dargestellt werden:
myFraction + yourFraction
Wenn eine Operatorfunktion als Friend-Funktion definiert ist, kann sie mit derselben Syntax wie für eine Memberfunktion implizit aufgerufen werden; sie kann jedoch auch wie folgt explizit aufgerufen werden:
operator+( myFraction, yourFraction )
Operatorfunktionen können ebenso wenig wie gewöhnliche Funktionen mit Argumenten aufgerufen werden, die eine Konvertierung mit Objekterstellung erfordern.
Der Debugger unterstützt keine überladenen Operatoren mit sowohl const- als auch Nicht-const-Versionen.Überladene Operatoren mit const und Nicht-const-Versionen werden häufig in der Standardvorlagenbibliothek verwendet.
Überladen
Ein Debuggerausdruck kann überladene Funktionen aufrufen, sofern eine exakte Übereinstimmung besteht bzw. die übereinstimmende Funktion keine Konvertierung erfordert, bei der ein Objekt erstellt werden muss.Wenn die calc-Funktion z. B. ein CFraction-Objekt als Parameter hat und die CFraction-Klasse einen Einzelargumentkonstruktor definiert, der eine ganze Zahl akzeptiert, verursacht der folgende Ausdruck einen Fehler:
calc( 23 )
Obwohl es eine zulässige Konvertierung gibt, um die ganze Zahl in das von calc erwartete CFraction-Objekt umzuwandeln, beinhaltet eine derartige Konvertierung die Erstellung eines Objekts und wird daher nicht unterstützt.
Rangfolge
Der C++-Bereichsoperator (::) hat in Debuggerausdrücken einen niedrigeren Stellenwert als in Quellcode.In C++-Quellcode hat dieser Operator absoluten Vorrang.Im Debugger wird dieser Operator vorrangig vor den unären Operatoren (!, &, * u. a.), jedoch erst nach den Operatoren Basis und Postfix (->, ++, --) behandelt.
Symbolformate
Debuggerausdrücke, die Symbole enthalten, werden auf dieselbe Weise wie im Quellcode eingegeben, vorausgesetzt, die Symbole befinden sich in einem Modul, das mit vollständigen Debuginformationen kompiliert wurde (/Zi oder /ZI).Bei der Eingabe eines Ausdrucks mit öffentlichen Symbolen, d. h. Symbolen, die in Bibliotheken oder mit /Zd kompilierten Modulen enthalten sind, müssen Sie den ergänzten Symbolnamen (wie im Objektcode zu finden) verwenden.Weitere Informationen hierzu finden Sie unter /Z7, /Zd, /Zi, /ZI (Debuginformationsformat).
Mithilfe der LINK-Option /MAP erhalten Sie eine Auflistung sämtlicher Namen im ergänzten und nicht ergänzten Format.Weitere Informationen hierzu finden Sie unter "/MAP" (Zuordnungsdatei generieren).
Die Namensergänzung wird verwendet, um typsichere Verknüpfungen zu erzwingen.Dies bedeutet, dass ausschließlich Namen und Verweise miteinander verknüpft werden, deren Rechtschreibung, Groß- und Kleinschreibung, Aufrufkonvention und Typ exakt übereinstimmen.
Mit der C-Aufrufkonvention (entweder implizit oder explizit mit dem _cdecl-Schlüsselwort) deklarierte Namen beginnen mit einem Unterstrich ( _ ).Die Funktion main kann z. B. als _main dargestellt werden.Namen, die als _fastcall deklariert sind, beginnen mit dem @-Symbol.
Bei C++ wird durch den ergänzten Namen neben der Aufrufkonvention auch der Symboltyp codiert.Dieses Namensformat kann sich als lang und schwer lesbar erweisen.Der Name beginnt mit mindestens einem Fragezeichen (?).Bei C++-Funktionen umfasst die Ergänzung den Gültigkeitsbereich der Funktion, die Typen der Funktionsparameter und den Rückgabetyp der Funktion.
Typumwandlung
Bei Verwendung einer Typumwandlung muss der Typ dem Debugger bekannt sein.Das Programm muss über ein weiteres Objekt dieses Typs verfügen.Mithilfe von typedef-Anweisungen erstellte Typen werden nicht unterstützt.