Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här artikeln beskrivs användningen av C++-uttryckssyntax med Felsökningsverktygen för Windows.
Felsökningsprogrammet accepterar två olika typer av numeriska uttryck: C++-uttryck och Microsoft Macro Assembler-uttryck (MASM). Vart och ett av dessa uttryck följer sina egna syntaxregler för indata och utdata.
Mer information om när varje syntaxtyp används finns i Utvärdera uttryck och kommandot utvärdera uttryck .
C++-uttrycksparsern stöder alla former av C++-uttryckssyntax. Syntaxen innehåller alla datatyper, inklusive pekare, flyttalsnummer och matriser samt alla C++ unary- och binära operatorer.
Rutorna Watch och Locals i felsökningsprogrammet använder alltid C++-uttrycksutvärderaren.
I följande exempel visar kommandot ?? evaluate C++ expression värdet för instruktionspekarens register.
0:000> ?? @eip
unsigned int 0x771e1a02
Vi kan använda funktionen C++ sizeof för att fastställa strukturens storlek.
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Ange uttrycksutvärderingen till C++
Använd .expr choose expression evaluator för att se standarduttrycksutvärderingen och ändra den till C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
När standarduttryckets utvärderare har ändrats kan kommandot ? evaluate expression användas för att visa C++-uttryck. I följande exempel visas värdet för instruktionspekarens register.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
För att lära dig mer om registerreferensen, se @eipRegistersyntax.
I det här exemplet läggs hexvärdet för 0xD till i eip-registret.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Register och pseudoregister i C++-uttryck
Du kan använda register och pseudoregister i C++-uttryck. @-tecknet måste adderas före registret eller pseudoregistret.
Uttrycksutvärderaren utför automatiskt korrekt typomvandling. Faktiska register och pseudoregister med heltalsvärde omvandlas till ULONG64. Alla adresser kastas till PUCHAR, $thread kastas till ETHREAD*, $proc kastas till EPROCESS*, $teb kastas till TEB*, och $peb kastas till PEB*.
I det här exemplet visas TEB.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
Du kan inte ändra ett register eller pseudoregister med en tilldelnings- eller bieffektoperator. Du måste använda kommandot r registers för att ändra dessa värden.
I följande exempel anges pseudoregistret till värdet 5 och visas sedan.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Mer information om register och pseudoregister finns i Registersyntax och Pseudoregistersyntax.
Tal i uttryck i C++
Tal i C++-uttryck tolkas som decimaltal, såvida du inte anger dem på ett annat sätt. Om du vill ange ett hexadecimalt heltal lägger du till 0x före talet. Om du vill ange ett oktalt heltal lägger du till 0 (noll) före talet.
Standardradixet för felsökningsprogrammet påverkar inte hur du anger C++-uttryck. Du kan inte ange ett binärt tal direkt, förutom genom att kapsla ett MASM-uttryck i C++-uttrycket.
Du kan ange ett hexadecimalt 64-bitarsvärde i formatet xxxxxxxx'xxxxxxxx. Du kan också utelämna gravaccenten ('). Båda formaten ger samma värde.
Du kan använda suffixen L, Uoch I64 med heltalsvärden. Den faktiska storleken på det tal som skapas beror på suffixet och talet som du anger. Mer information om den här tolkningen finns i en C++-språkreferens.
Utdata från C++-uttrycksutvärderingen behåller den datatyp som C++-uttrycksreglerna anger. Men om du använder det här uttrycket som ett argument för ett kommando skapas alltid en cast. Du behöver till exempel inte omvandla heltalsvärden till pekare när de används som adresser i kommandoargument. Om uttryckets värde inte kan omvandlas giltigt till ett heltal eller en pekare uppstår ett syntaxfel.
Du kan använda prefixet 0n (decimal) för vissa utdata, men du kan inte använda det för C++-uttrycksindata.
Tecken och strängar i C++-uttryck
Du kan ange ett tecken genom att omge det med enkla citattecken ('). Standard C++ escape-tecken är tillåtna.
Du kan ange strängliteraler genom att omge dem med dubbla citattecken ("). Du kan använda \" som en escape-sekvens i en sådan sträng. Strängar har dock ingen betydelse för uttrycksutvärderaren.
Symboler i C++-uttryck
I ett C++-uttryck tolkas varje symbol enligt dess typ. Beroende på vad symbolen refererar till kan den tolkas som ett heltal, en datastruktur, en funktionspekare eller någon annan datatyp. Ett syntaxfel uppstår om du använder en symbol som inte motsvarar en C++-datatyp, till exempel ett omodifierat modulnamn, i ett C++-uttryck.
Du kan använda en grav accent (') eller en apostrofer (') i ett symbolnamn endast om du lägger till ett modulnamn och utropstecken före symbolnamnet. När du lägger till avgränsarna < och > efter ett mallnamn, kan du lägga till blanksteg mellan dessa avgränsare.
Om symbolen kan vara tvetydig kan du lägga till ett modulnamn och ett utropstecken (!) eller bara ett utropstecken före symbolen. Om du vill ange att en symbol ska vara lokal utelämnar du modulnamnet och inkluderar ett dollartecken och ett utropstecken ($!) före symbolnamnet. Mer information om symboligenkänning finns i Symbolsyntax och symbolmatchning.
Strukturer i C++-uttryck
C++-uttrycksutvärderingen omvandlar pseudoregister till lämpliga typer. Till exempel $teb är kastad som en TEB*.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
I följande exempel visas process-ID:t i TEB-strukturen som visar användningen av en pekare till en medlem i den refererade strukturen.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Operatorer i C++-uttryck
Du kan använda parenteser för att åsidosätta prioritetsregler.
Om du omger en del av ett C++-uttryck inom parenteser och lägger till två vid tecken (@@) före uttrycket tolkas uttrycket enligt MASM-uttrycksregler. Du kan inte lägga till ett blanksteg mellan de två vid tecken och den inledande parentesen. Det slutliga värdet för det här uttrycket skickas till C++-uttrycksutvärderingen som ett ULONG64 värde. Du kan också ange uttrycksutvärderaren genom att använda @@c++( ... ) eller @@masm( ... ).
Datatyper anges som vanligt på C++-språket. Symbolerna som anger matriser ([ ]), pekarmedlemmar (-), UDT-medlemmar> (.) och medlemmar i klasser (::) känns alla igen. Alla aritmetiska operatorer stöds, inklusive tilldelnings- och bieffektoperatorer. Du kan dock inte använda operatorerna new, deleteoch throw och du kan inte anropa en funktion.
Pekarearitmetik stöds och förskjutningar skalas korrekt. Observera att du inte kan lägga till en förskjutning till en funktionspekare. Om du måste lägga till en förskjutning till en funktionspekare ska du först omvandla förskjutningen till en teckenpekare.
Precis som i C++ uppstår ett syntaxfel om du använder operatorer med ogiltiga datatyper. Felsökarens C++-uttrycksparser använder något mer avslappnade regler än de flesta C++-kompilatorer, men alla större regler tillämpas. Du kan till exempel inte flytta ett icke-heltalsvärde.
Du kan använda följande operatorer. Operatorerna i varje cell har företräde framför operatorer i lägre celler. Operatorer i samma cell har samma prioritet och parsas från vänster till höger.
Precis som med C++ slutar uttrycksutvärderingen när dess värde är känt. Med det här slutet kan du effektivt använda uttryck som ?? myPtr && *myPtr.
Referens och typgjutning
| Operatör | Innebörd |
|---|---|
| Uttryck // Kommentar | Ignorera alla efterföljande text |
| Klass :: Medlem | Medlem i klassen |
| Klass ::~Medlem | En medlem av klassen (destruktor) |
| :: Namn | Global |
| Struktur. Fält | Fält i en struktur |
| Pekare –>fält | Fält i refererad struktur |
| Namn [heltal] | Matris underordnad |
| Lvalue ++ | Ökning (efter utvärdering) |
| Lvalue -- | Minskning (efter utvärdering) |
| < dynamic_casttyp>(Värde) | Typecast (utförs alltid) |
| static_cast<typ>(Värde) | Typecast (utförs alltid) |
| < reinterpret_casttyp>(Värde) | Typecast (utförs alltid) |
| < const_casttyp>(Värde) | Typecast (utförs alltid) |
Värdeåtgärder
| Operatör | Innebörd |
|---|---|
| (typ) Värde | Typecast (utförs alltid) |
| sizeofvalue | Uttrycksstorlek |
| sizeof( typ ) | Storlek på datatyp |
| ++ Lvalue | Öka (före utvärdering) |
| -- Lvalue | Minskning (före utvärdering) |
| ~ Värde | Bitkomplement |
| ! Value | Inte (booleskt) |
| Value | Unärt minus |
| + Värde | Unary plus |
| &LValue | Adress för datatyp |
| Value | Dereference |
| Struktur. pekare | Pekare till medlem i strukturen |
| Pekare –> * pekare | Pekare till medlem i refererad struktur |
Aritmetik
| Operatör | Innebörd |
|---|---|
| Värdevärde | Multiplikation |
| Värde / Värde | avdelning |
| Värde % Värde | Modulus |
| Värde + Värde | Tillägg |
| Värde - Värde | Subtraktion |
| Värde<<Värde | Bitvis skift vänster |
| Värde>>Värde | Bitvis skift höger |
| Värde<Värde | Mindre än (jämförelse) |
| Värde<= Värde | Mindre än eller lika med (jämförelse) |
| Värde>Värde | Större än (jämförelse) |
| Värde>= Värde | Större än eller lika med (jämförelse) |
| Värde == Värde | Lika (jämförelse) |
| Värde != Värde | Inte lika med (jämförelse) |
| Värde och värde | Bitvis OCH |
| Värde ^ Värde | Bitvis XOR (exklusiv ELLER) |
| Värde | Värde | Bitvis ELLER |
| Värde & värde | Logiskt OCH |
| Värde || Värde | Logiskt ELLER |
I följande exempel antas att pseudoregistren är inställda som visat.
0:000> r $t0 = 0
0:000> r $t1 = 1
0:000> r $t2 = 2
0:000> ?? @$t1 + @$t2
unsigned int64 3
0:000> ?? @$t2/@$t1
unsigned int64 2
0:000> ?? @$t2|@$t1
unsigned int64 3
Uppgift
| Operatör | Innebörd |
|---|---|
| Lvalue = Värde | Tilldela |
| Lvalue *= Värde | Multiplicera och tilldela |
| L-värde /= Värde | Dela upp och tilldela |
| Lvalue %= Värde | Modulo och tilldelning |
| Lvalue += Värde | Lägga till och tilldela |
| Lvalue -= Värde | Subtrahera och tilldela |
| Lvalue<<= Värde | Flytta åt vänster och tilldela |
| Lvalue>>= Värde | Flytta åt höger och tilldela |
| LValue &= Värde | OCH och tilldela |
| Lvärde |= Värde | eller tilldela |
| Lvalue ^= Värde | XOR och tilldela |
Utvärdering
| Operatör | Innebörd |
|---|---|
| Värde ? Värde : Värde | Villkorsstyrd utvärdering |
| Värde , värde | Utvärdera alla värden och ta sedan bort alla utom det högra värdet |
Makron i C++-uttryck
Du kan använda makron i C++-uttryck. Du måste lägga till ett taltecken (#) före makrona.
Du kan använda följande makron. Dessa makron har samma definitioner som Microsoft Windows-makron med samma namn. Windows-makrona definieras i Winnt.h.
| Makro | Returvärde |
|---|---|
| #CONTAINING_RECORD(Adress, typ, fält) | Returnerar basadressen för en instans av en struktur, med tanke på typen av struktur och adressen för ett fält i strukturen. |
| #FIELD_OFFSET(typ, fält) | Returnerar byteförskjutningen för ett namngivet fält i en känd strukturtyp. |
| #RTL_CONTAINS_FIELD(Struct, Storlek, Fält) | Anger om den angivna bytestorleken innehåller önskat fält. |
| #RTL_FIELD_SIZE(typ, fält) | Returnerar storleken på ett fält i en struktur av känd typ, utan att kräva typen av fält. |
| #RTL_NUMBER_OF(Array) | Returnerar antalet element i en matris med statisk storlek. |
| #RTL_SIZEOF_THROUGH_FIELD(typ, fält) | Returnerar storleken på en struktur av känd typ, upp till och med ett angivet fält. |
Det här exemplet visar hur makrot #FIELD_OFFSET används för att beräkna byteförskjutningen till ett fält i en struktur.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
Se även
MASM-uttryck jämfört med C++-uttryck