共用方式為


C++ 數字和運算子

本文說明如何搭配 Windows 偵錯工具使用 C++ 運算式語法。

偵錯工具接受兩種不同類型的數值運算式:C++ 運算式和 Microsoft 巨集組合器 (MASM) 運算式。 這些運算式中的每一個都遵循自己的輸入和輸出語法規則。

如需何時使用每一個語法類型的詳細資訊,請參閱 評估運算式? evaluate 運算式 指令。

C++ 運算式剖析器支援所有形式的 C++ 運算式語法。 語法包括所有資料類型,包括指標、浮點數和陣列,以及所有 C++ 一元和二進位運算子。

偵錯工具中的 WatchLocals 視窗一律會使用 C++ 運算式評估器。

在下列範例中, ?? evaluate 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 運算式。

您可以以 xxxxxxxx'xxxxxxxx 格式輸入十六進位 64 位元值。 您也可以省略重音符號 (')。 兩種格式都會產生相同的值。

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

C++ 運算式評估器的 輸出 會保留 C++ 運算式規則指定的資料類型。 不過,如果您使用此運算式作為命令的引數,則一律會進行轉換。 例如,當整數值用作命令引數中的位址時,您不需要將整數值轉換給指標。 如果運算式的值無法有效轉換成整數或指標,則會發生語法錯誤。

您可以針對某些 輸出使用 0n(十進位)前置符號,但無法將其用於 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 結構中的程序 ID,並展示如何使用指向參考結構成員的指標。

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

C++ 運算式中的運算子

您可以使用括弧來置換優先順序規則。

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

資料類型會像往常一樣在 C++ 語言中指出。 表示陣列 ([ ])、指標成員 (->)、UDT 成員 (.) 和類別成員 (::) 的符號都會被辨識。 支援所有算術運算子,包括賦值和副作用運算子。 但是,您不能使用 newdeletethrow 運算子,也無法實際呼叫函數。

支援指針運算,並且正確調整偏移量。 請注意,您無法將偏移量新增至函式指標。 如果您必須將位移量新增至函式指標,請先將位移量轉型為字元指標。

如同在 C++ 中,如果您使用資料類型無效的運算子,則會發生語法錯誤。 偵錯工具的 C++ 運算式剖析器使用比大部分 C++ 編譯器稍微寬鬆的規則,但會強制執行所有主要規則。 例如,您無法移動非整數值。

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

與 C++ 一樣,運算式評估在其值已知時結束。 此結尾使您能夠有效地使用諸如 ?? myPtr && *myPtr.

參考和類型轉換

操作員 意義
// 註解 忽略所有後續文字
班級 :: 會員 班級成員
班級 ::~會員 類別成員 (析構函數)
:: 名稱 全球
結構欄位 結構中的欄位
指標->欄位 參考結構中的欄位
名稱 [整數] 陣列下標
LValue ++ 增加(評估後)
LValue -- 遞減(評估後)
dynamic_cast<>( 類型轉換 (一律執行)
static_cast<類型>( 類型轉換 (一律執行)
reinterpret_cast<type>(Value 類型轉換 (一律執行)
const_cast<>(Value 類型轉換(一律執行)

價值操作

操作員 意義
類型 類型轉換 (一律執行)
sizeofvalue 表達式大小
sizeof類型 資料類型的大小
++ LValue 增量(評估前)
-- LValue 遞減(評估前)
~ 價值 位元補碼
! 價值 不是 (布林值)
價值 一元減號
+ 價值 一元加號
& LValue 資料類型的位址
價值 取消參考
結構指標 結構成員的指標
指標 -> * 指標 參考結構成員的指標

算術

操作員 意義
Value Value 乘法
/ 部門
% 模數
+ 加法
- 減法
<< 按位左移
>> 按位向右移動
< 小於(比較)
價值<= 價值 小於或等於 (比較)
> 大於 (用於比較)
>= 大於或等於 (比較)
== 相等(比較)
!= 不相等(比較)
價值價值 位 AND
價值 ^ 價值 位元異或(XOR, exclusive OR)
| 位 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

任務

操作員 意義
L值 = 指派
L值 *= 乘法 和賦值
L值 /= 劃分和分配
L值 %= 模數和賦值
L值 += 新增和分配
L值 -= 減法和賦值
LValue<<= Value 左移並分配
L值>>= 向右移動並分配
LValue &= AND 並分配
LValue |= Value OR 並指派
LValue ^= Value 異或並分配

評估

操作員 意義
價值 條件式評估
評估所有值,然後捨棄最右邊值以外的所有值

C++ 運算式中的巨集

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

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

巨集 返回值
#CONTAINING_RECORD(地址、類型、欄位 傳回結構實例的基底位址,指定結構的類型和結構內欄位的位址。
#FIELD_OFFSET(類型、欄位 傳回已知結構類型中具名字段的位元組位移。
#RTL_CONTAINS_FIELD(結構體、大小、欄位 指出給定的位元組大小是否包含所需的欄位。
#RTL_FIELD_SIZE(類型、欄位 傳回已知類型結構中欄位的大小,而不需要欄位的類型。
#RTL_NUMBER_OF(陣列 傳回靜態大小陣列中的元素數目。
#RTL_SIZEOF_THROUGH_FIELD(類型、欄位 傳回已知類型結構的大小,包括指定的欄位。

此範例示範如何使用巨集 #FIELD_OFFSET 來計算結構中欄位的位元組位移。

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

另請參閱

MASM 運算式與 C++ 運算式

?? 評估 C++ 運算式

? 評估運算式

.expr 選擇運算式評估器

符號擴展

混合運算式範例