Sdílet prostřednictvím


Čísla a operátory jazyka C++

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++

?? vyhodnocení výrazu C++

? vyhodnotit výraz

.expr vyber hodnotitele výrazů

Rozšíření podpisu

Příklady smíšených výrazů