Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek popisuje použití syntaxe výrazů jazyka C++ s nástroji pro ladění Systému Windows.
Ladicí program přijímá dva různé druhy číselných výrazů: výrazy C++ a výrazy MASM (Microsoft Macro Assembler). Každý z těchto výrazů se řídí vlastními pravidly syntaxe pro vstup a výstup.
Další informace o tom, kdy se jednotlivé typy syntaxe používají, najdete v tématu Vyhodnocení výrazů a příkazu ?evaluate expression .
Analyzátor výrazů jazyka C++ podporuje všechny formy syntaxe výrazů jazyka C++. Syntaxe zahrnuje všechny datové typy, včetně ukazatelů, čísel s plovoucí desetinou čárkou a polí a všech unárních a binárních operátorů jazyka C++.
Okna Sledování a Místní proměnné v ladicím programu vždy používají vyhodnocovač výrazů jazyka C++.
V následujícím příkladu příkaz ?? evaluate C++ výraz zobrazí hodnotu registru ukazatele instrukce.
0:000> ?? @eip
unsigned int 0x771e1a02
K určení velikosti struktur můžeme použít funkci C++ sizeof .
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Nastavení vyhodnocovače výrazů na C++
Pomocí vyhodnocovače výrazů .expr zobrazíte výchozí vyhodnocovač výrazů a změníte ho na C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
Po změně výchozího vyhodnocovače výrazů je možné k zobrazení výrazů jazyka C++ použít příkaz pro vyhodnocení výrazu ? . Následující příklad zobrazí hodnotu registru ukazatele instrukce.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Další informace o referenční dokumentaci @eip k registru najdete v tématu Syntaxe registrace.
V tomto příkladu se do registru eip přičte šestnáctková hodnota 0xD.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Registry a pseudoregistry ve výrazech jazyka C++
V rámci výrazů jazyka C++ můžete použít registry a pseudoregistry. Znak @ musí být přidán před registr nebo pseudoregistr.
Vyhodnocovač výrazů automaticky provádí správné přetypování. Skutečné registry a pseudoregistry s celočíselnou hodnotou jsou přetypované na ULONG64. Všechny adresy se přetypují na PUCHAR, $thread se přetypuje na ETHREAD*, $proc se přetypuje na EPROCESS*, $teb se přetypuje na TEB* a $peb se přetypuje na PEB*.
Tento příklad zobrazí 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
Nemůžete změnit registr ani pseudoregistr pomocí přiřazovacího nebo vedlejšího operátoru. Ke změně těchto hodnot musíte použít příkaz r registers .
Následující příklad nastaví pseudoregistr na hodnotu 5 a pak ho zobrazí.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Další informace o registrech a pseudoregistrech naleznete v tématu Syntaxe registrace a Pseudoregistr syntaxe.
Čísla ve výrazech jazyka C++
Čísla ve výrazech jazyka C++ se interpretují jako desetinná čísla, pokud je nezadáte jiným způsobem. Pokud chcete zadat šestnáctkové celé číslo, přidejte 0x před číslo. Pokud chcete zadat osmičkové celé číslo, přidejte 0 (nula) před číslo.
Výchozí radix ladicího programu nemá vliv na zadávání výrazů jazyka C++. Binární číslo nelze zadat přímo, s výjimkou vnoření výrazu MASM do výrazu C++.
Hexadecimální 64bitovou hodnotu můžete zadat ve formátu xxxxxxxx'xxxxxxxx. Můžete také vynechat přízvuk (`). Oba formáty vytvoří stejnou hodnotu.
Můžete použít přípony L, U a I64 s celočíselnými hodnotami. Skutečná velikost vytvořeného čísla závisí na příponě a zadaném čísle. Další informace o této interpretaci naleznete v referenční dokumentaci jazyka C++.
Výstup vyhodnocovače výrazů jazyka C++ uchovává datový typ, který určují pravidla výrazu jazyka C++. Pokud však tento výraz použijete jako argument pro příkaz, provede se vždy přetypování. Například nemusíte přetypovat celočíselné hodnoty na ukazatele, když se v argumentech příkazu používají jako adresy. Pokud hodnotu výrazu nelze platně přetypovat na celé číslo nebo ukazatel, dojde k chybě syntaxe.
Pro nějaký výstup můžete použít předponu 0n (desítková), ale nemůžete ji použít pro vstup výrazu jazyka C++.
Znaky a řetězce ve výrazech jazyka C++
Znak můžete zadat tak, že ho obklopíte jednoduchými uvozovkami ('). Jsou povoleny standardní únikové znaky jazyka C++.
Řetězcové literály můžete zadat tak, že je obklopíte dvojitými uvozovkami ("). Jako únikovou sekvenci v rámci takového řetězce můžete použít \". Řetězce ale nemají význam pro vyhodnocovač výrazů.
Symboly ve výrazech jazyka C++
Ve výrazu jazyka C++ se každý symbol interpretuje podle svého typu. V závislosti na tom, co symbol odkazuje, může být interpretován jako celé číslo, datová struktura, ukazatel funkce nebo jakýkoli jiný datový typ. K chybě syntaxe dojde, pokud v rámci výrazu jazyka C++ použijete symbol, který neodpovídá datovému typu C++, jako je název nemodifikovaného modulu.
V názvu symbolu můžete použít opačný přízvuk (`) nebo apostrof (') pouze v případě, že před názvem symbolu přidáte název modulu a vykřičník. Když za název šablony přidáte oddělovače < a >, můžete mezi tyto oddělovače přidat mezery.
Pokud může být symbol nejednoznačný, můžete před symbol přidat název modulu a vykřičník (!) nebo jenom vykřičník. Pokud chcete určit, že symbol má být místní, vynecháte název modulu a před název symbolu uveďte znak dolaru a vykřičník ($!). Další informace o rozpoznávání symbolů naleznete v tématu Syntaxe symbolů a porovnávání symbolů.
Struktury ve výrazech jazyka C++
Vyhodnocovače výrazů jazyka C++ přetypuje pseudoregistry na příslušné typy. Například je $teb přetypován jako 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
Následující příklad zobrazí ID procesu ve struktuře TEB zobrazující použití ukazatele na člen odkazované struktury.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Operátory ve výrazech jazyka C++
K přepsání prioritních pravidel můžete použít závorky.
Pokud část výrazu v C++ uzavřete do závorek a před výraz přidáte dva znaky zavináče (@@), bude výraz interpretován podle pravidel výrazu MASM. Mezi dvě zavináče a levou závorku nemůžete přidat mezeru. Konečná hodnota tohoto výrazu se předá vyhodnocovači výrazů C++ jako hodnota ULONG64. Můžete také zadat vyhodnocovač výrazů pomocí @@c++( ... ) nebo @@masm( ... ).
Datové typy jsou v jazyce C++ označené obvyklým způsobem. Symboly, které označují pole ([ ]), členy ukazatelů (->), členy UDT (.) a členy tříd (::), jsou všechny rozpoznány. Podporují se všechny aritmetické operátory, včetně operátorů přiřazení a vedlejších efektů. Nemůžete použít operátory new, delete a throw, a nemůžete ve skutečnosti volat funkci.
Ukazatelová aritmetika je podporovaná a offsety se škálují správně. Všimněte si, že ke ukazateli funkce nelze přidat posun. Pokud potřebujete přidat posun k ukazateli na funkci, nejprve přetypujte tento posun na ukazatel typu char.
Stejně jako v jazyce C++, pokud používáte operátory s neplatnými datovými typy, dojde k chybě syntaxe. Analyzátor výrazů C++ v ladicím programu používá pravidla, která jsou mírně uvolněnější než pravidla většiny kompilátorů C++, ale všechna hlavní pravidla jsou i přesto dodržována. Nemůžete například posunout neceločíselnou hodnotu.
Můžete použít následující operátory. Operátory v každé buňce mají přednost před operátory v dolních buňkách. Operátory v rámci stejné úrovně mají stejnou prioritu a jsou zpracovávány zleva doprava.
Stejně jako u jazyka C++ končí vyhodnocení výrazu, když je jeho hodnota známá. Tento konec umožňuje efektivně používat výrazy, jako je ?? myPtr && *myPtr.
Přetypování odkazů a typů
| Operátor | Význam |
|---|---|
| Výraz // Komentář | Ignorovat veškerý následující text |
| Třída :: Člen | Člen třídy |
| Třída ::~Člen | Člen třídy (destruktor) |
| :: Název | Globální |
| Struktura . Pole | Pole ve struktuře |
| Ukazatel –>pole | Pole v odkazované struktuře |
| Název [celé číslo] | Dolní index pole |
| LValue ++ | Přírůstek (po vyhodnocení) |
| LValue -- | Dekrementace (po vyhodnocení) |
| dynamic_cast<type>(Value) | Přetypování (provedeno vždy) |
| < static_casttyp>(Hodnota) | Typecast (vždy provedeno) |
| < reinterpret_casttyp>(Hodnota) | Typové přetypování (prováděno vždy) |
| const_cast<type>(Value) | Typový převod (vždy proveden) |
Operace s hodnotami
| Operátor | Význam |
|---|---|
| (typ) Hodnota | Přetypování (vždy provedeno) |
| sizeofvalue | Velikost výrazu |
| sizeof( typ ) | Velikost datového typu |
| ++ LValue | Přírůstek (před vyhodnocením) |
| -- LValue | Dekrementace (před vyhodnocením) |
| ~ hodnota | Doplněk bitu |
| ! Hodnota | Ne (logická hodnota) |
| Hodnota | Unární mínus |
| + hodnota | Unární plus |
| & LValue | Adresa datového typu |
| Hodnota | Dereferencování |
| Struktura . ukazatel | Ukazatel na člen struktury |
| Ukazatel -> * Ukazatel | Ukazatel na člen odkazované struktury |
Aritmetika
| Operátor | Význam |
|---|---|
| Hodnota | Násobení |
| Hodnota / Hodnota | Oddělení |
| Hodnota % Hodnota | Modul |
| Hodnota + Hodnota | Přidání |
| Hodnota - Hodnota | Odčítání |
| Hodnota<<Hodnota | Bitový posun směrem doleva |
| Hodnota>>Hodnota | Bitový posun doprava |
| Hodnota<Hodnota | Menší než (porovnání) |
| Hodnota<= Hodnota | Menší než nebo rovno (porovnání) |
| Hodnota>Hodnota | Větší než (porovnání) |
| Hodnota>= Hodnota | Větší než nebo rovno (porovnání) |
| Hodnota == Hodnota | Rovná se (porovnání) |
| Hodnota != Hodnota | Nerovná se (porovnání) |
| Hodnota a hodnota | Bitový operátor AND |
| Hodnota ^ Hodnota | Bitwise XOR (exkluzivní OR) |
| Hodnota | Hodnota | Bitový operátor OR |
| Hodnota & hodnota | Logická operace AND |
| Hodnota || Hodnota | Logické NEBO |
Následující příklady předpokládají, že pseudoregistry jsou nastavené, jak je znázorněno.
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
Zadání
| Operátor | Význam |
|---|---|
| LValue = Hodnota | Přiřadit |
| LValue *= Hodnota | Vynásobit a přiřadit |
| LValue /= Value | Dělit a přiřazovat |
| LValue %= Hodnota | Modulo a přiřazení |
| LValue += Hodnota | Přidat a přiřadit |
| LValue -= Hodnota | Odečtení a přiřazení |
| LValue<<= Hodnota | Posun doleva a přiřazení |
| LValue>>= Hodnota | Posunout doprava a přiřadit |
| LValue &= Value | AND a přiřadit |
| LValue |= Hodnota | OR a přiřazení |
| LValue ^= Hodnota | XOR a přiřazení |
Vyhodnocení
| Operátor | Význam |
|---|---|
| Hodnota ? Hodnota : Hodnota | Podmíněné vyhodnocení |
| Hodnota , hodnota | Vyhodnoťte všechny hodnoty a potom zahoďte všechny kromě hodnoty úplně vpravo. |
Makra ve výrazech jazyka C++
Makra můžete použít ve výrazech jazyka C++. Před makra musíte přidat znak čísla (#).
Můžete použít následující makra. Tato makra mají stejné definice jako makra systému Microsoft Windows se stejným názvem. Makra systému Windows jsou definována v souboru Winnt.h.
| Makro | Návratová hodnota |
|---|---|
| #CONTAINING_RECORD(adresa, typ, pole) | Vrátí základní adresu instance struktury vzhledem k typu struktury a adrese pole v rámci struktury. |
| #FIELD_OFFSET(Typ, Pole) | Vrátí posun bajtů pojmenovaného pole ve známém typu struktury. |
| #RTL_CONTAINS_FIELD(Struktura, velikost, pole) | Určuje, jestli daná velikost bajtu obsahuje požadované pole. |
| #RTL_FIELD_SIZE(Typ, pole) | Vrátí velikost pole ve struktuře známého typu, aniž by bylo nutné zadat typ pole. |
| #RTL_NUMBER_OF(Pole) | Vrátí počet prvků v poli se statickou velikostí. |
| #RTL_SIZEOF_THROUGH_FIELD(Typ, Pole) | Vrátí velikost struktury známého typu, včetně velikosti zadaného pole. |
Tento příklad ukazuje použití #FIELD_OFFSET makra k výpočtu posunu bajtů na pole ve struktuře.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
Viz také
Výrazy MASM vs. výrazy jazyka C++