C++數位和運算符

本文說明搭配 Windows 偵錯工具使用C++表達式語法。

調試程式接受兩種不同類型的數值表達式:C++表達式和Microsoft宏組合器 (MASM) 表達式。 每個表達式都會遵循自己的輸入和輸出語法規則。

如需何時使用每個語法類型的詳細資訊,請參閱 評估表達式? evaluate expression 命令。

C++運算式剖析器支援所有形式的C++表達式語法。 語法包含所有數據類型,包括指標、浮點數和陣列,以及所有C++一元和二元運算符。

調試程式中的 [監看式] 和 [局部變數] 視窗一律使用C++表達式評估工具。

在下列範例中 ,?評估C++表達式 命令會顯示指令指標緩存器的值。

0:000> ?? @eip
unsigned int 0x771e1a02

我們可以使用 C++ sizeof 函式來判斷結構的大小。

0:000> ?? (sizeof(_TEB))
unsigned int 0x1000

將表達式評估工具設定為 C++

使用 .expr 選擇表示式評估工具以查看預設表達式評估工具,並將它變更為C++。

0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

變更預設表達式評估工具之後, 可以使用 ? evaluate expression 命令來顯示C++運算式。 下列範例會顯示指令指標緩存器的值。

0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02

若要深入瞭解 @eip 緩存器參考,請參閱 註冊語法

在此範例中,0xD的十六進位值會新增至 eip 快取器。

0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f

C++ 運算式中的緩存器和虛擬緩存器

您可以在C++運算式中使用緩存器和虛擬緩存器。 必須在快取器或虛擬緩存器之前加入 @ 符號。

表達式評估工具會自動執行適當的轉換。 實際快取器和整數值虛擬快取器會轉換成 ULONG64。 所有位址都會轉換成 PUCHAR$thread 轉換成 ETHREAD*$proc EPROCESS*轉換成 、 $teb 轉換成 、轉換成 TEB*,而且 $peb 會轉換成 PEB*

此範例會顯示 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

您無法透過指派或副作用運算符來變更快取器或虛擬緩取器。 您必須使用 r registers 命令來變更這些值。

下列範例會將虛擬緩存器設定為 5,然後顯示它。

0:000> r $t0 = 5

0:000> ?? @$t0
unsigned int64 5

如需緩存器和虛擬緩存器的詳細資訊,請參閱 註冊語法虛擬緩存器語法

C++運算式中的數位

除非以其他方式指定數字,否則C++運算式中的數位會解譯為十進位數。 若要指定十六進位整數,請在數位前面加上 0x。 若要指定八進位整數,請在數位前面加上 0 (零)。

默認調試程式基底不會影響您輸入C++表達式的方式。 除了在C++運算式內巢狀 MASM 運算式之外,您無法直接輸入二進位數。

您可以在xxxxxxxxxx'xxxxxxxx格式中輸入十六進位64位值。 您也可以省略墳墓口音 (')。 這兩種格式會產生相同的值。

您可以使用 LUI64 後綴搭配整數值。 所建立數位的實際大小取決於後綴和您輸入的數位。 如需此解譯的詳細資訊,請參閱C++語言參考。

C++運算式評估工具的輸出會保留C++運算式規則所指定的數據類型。 不過,如果您使用這個運算式做為命令的自變數,則一律會進行轉換。 例如,當它們當做命令自變數中的位址使用時,您不需要將整數值轉換成指標。 如果表達式的值無法有效轉換成整數或指標,就會發生語法錯誤。

您可以針對某些輸出使用 0n (decimal) 前置詞,但無法將其用於C++表達式輸入。

C++運算式中的字元和字串

您可以用單引號 (') 括住字元來輸入字元。 允許標準C++逸出字元。

您可以用雙引號括住字串常值來輸入字串常值。」。 您可以使用 \“ 作為這類字串內的逸出序列。 不過,字串對表達式評估工具沒有意義

C++運算式中的符號

在C++表達式中,每個符號都會根據其類型來解譯。 視符號所參考的內容而定,它可能會解譯為整數、數據結構、函式指標或任何其他數據類型。 如果您在C++運算式中使用未對應至C++數據類型的符號,例如未修改的模組名稱,就會發生語法錯誤。

只有當您在符號名稱前面新增模組名稱和驚嘆號時,才可以在符號名稱中使用嚴重輔色 (') 或單引號 (')。 當您在 < 範本名稱後面新增 和 > 分隔符時,可以在這些分隔符之間新增空格。

如果符號可能模棱兩可,您可以新增模組名稱和驚嘆號 (!) 或只在符號之前驚歎號。 若要指定符號應該是本機符號,請省略模塊名稱,並在符號名稱之前包含貨幣符號和驚嘆號 ($!)。 如需符號辨識的詳細資訊,請參閱 符號語法和符號比對

C++運算式中的結構

C++運算式評估工具會將虛擬緩存器轉換成其適當的類型。 例如, $teb 會轉換成 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

下列範例會顯示 TEB 結構中的進程識別碼,其中顯示參考結構成員的指標用法。

0:000> ??  @$teb->ClientId.UniqueProcess
void * 0x0000059c

C++運算式中的運算符

您可以使用括弧來覆寫優先順序規則。

如果您在表達式前面加上括弧中C++表達式的一部分,並在表達式前面加上兩個符號(@@),則表達式會根據MASM運算式規則來解譯。 您無法在符號和左括弧之間新增兩個空格。 此表達式的最終值會傳遞至C++表達式評估工具做為ULONG64值。 您也可以使用 @@c++( ... )@@masm( ... )指定表示式評估工具。

數據類型會以C++語言一般表示。 表示陣列 ([ ])、指標成員 (->)、UDT 成員 (.) 和類別成員 (::) 的符號全都會被辨識。 支援所有算術運算符,包括指派和副作用運算符。 不過,您無法使用 newdeletethrow 運算子,而且實際上無法呼叫函式。

支援指標算術,並正確調整位移。 請注意,您無法將位移新增至函式指標。 如果您必須將位移新增至函式指標,請先將位移轉換成字元指標。

如同C++,如果您使用具有無效數據類型的運算符,就會發生語法錯誤。 調試程式的C++表達式剖析器會使用比大多數C++編譯程式稍微寬鬆的規則,但會強制執行所有主要規則。 例如,您無法移動非整數值。

您可以使用下列運算子。 每個儲存格中的運算元優先於較低儲存格中的運算元。 相同儲存格中的運算子的優先順序相同,且會從左至右剖析。

如同C++,表達式評估會在已知其值時結束。 這個結尾可讓您有效地使用 表示式,例如 ?? myPtr && *myPtr

參考和型別轉換

運算子 意義
表達式 // 批注 忽略所有後續文字
類別 :: 成員 類別的成員
類別 ::~Member 類別的成員 (解構函式)
:: 名稱 全球
結構欄位 結構中的欄位
指標 ->Field 參考結構中的欄位
名稱 [integer] 陣列註標
LValue ++ 遞增 (評估後)
LValue -- 遞減 (評估後)
<dynamic_cast類型>(值) Typecast (一律執行)
<static_cast類型>(值) Typecast (一律執行)
<reinterpret_cast類型>(值) Typecast (一律執行)
<const_cast類型>(值) Typecast (一律執行)

值作業

運算子 意義
type Typecast (一律執行)
sizeof 表達式的大小
sizeof類型 數據類型的大小
++ LValue 遞增 (評估前)
-- LValue 遞減 (評估前)
~ 位補碼
! Not (布林值)
一元減號
+ 一元加號
& LValue 數據類型的位址
Dereference
結構指標 結構成員的指標
指標 -> * 指標 參考結構成員的指標

算術

運算子 意義
乘法
/ 除法
% 模數
+ 加法
- 減法
<< 位移左
>> 位向右移位
< 小於 (比較)
Value= Value< 小於或等於 (比較)
> 大於 (比較)
Value= Value> 大於或等於 (比較)
== 相等 (比較)
Value != Value 不相等(比較)
位元 AND
^ 位 XOR (獨佔 OR)
| 位元 OR
Value && Value 邏輯 AND
|| 邏輯 OR

下列範例假設已設定虛擬緩存器,如下所示。

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

指派

運算子 意義
LValue = 指派
LValue *= 相乘 和指派
LValue /= 除並指派
LValue %= 取餘數並指派
LValue += 加並指派
LValue -= 減並指派
LValue<<= 向左移並指派
LValue>>= 向右移位並指派
LValue &= AND 和指派
LValue |= OR 並指派
LValue ^= XOR 並指派

評估

運算子 意義
值: 條件式評估
值、 評估所有值,然後捨棄最右邊值以外的所有值

C++運算式中的宏

您可以在C++運算式中使用宏。 您必須在宏之前新增數字符號 (#)。

您可以使用下列宏。 這些宏的定義與具有相同名稱的 windows 宏Microsoft相同。 Windows 宏定義於 中 Winnt.h

Macro 傳回值
#CONTAINING_RECORD(Address, Type, Field 傳回 結構實例的基位址,指定 結構的類型和 結構內欄位的位址。
#FIELD_OFFSET(Type, Field 傳回已知結構類型中具名字段的位元組位移。
#RTL_CONTAINS_FIELD(結構、大小、欄位 指出指定的位元組大小是否包含所需的欄位。
#RTL_FIELD_SIZE(Type, Field 傳回已知型別結構中的字段大小,而不需要欄位的類型。
#RTL_NUMBER_OF(Array 傳回靜態大小陣列中的項目數目。
#RTL_SIZEOF_THROUGH_FIELD(Type, Field 傳回已知型別結構的大小,向上並包含指定的欄位。

這個範例示範如何使用 #FIELD_OFFSET 宏來計算 結構中欄位的位元組位移。

0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2

另請參閱

MASM 運算式與C++表達式

?? 評估C++表達式

? 評估表達式

.expr 選擇表示式評估工具

簽署延伸模組

混合表達式範例