原生 C++ 中的運算式
偵錯工具可接受大部分 Microsoft 和 ANSI C/C++ 運算式。偵錯工具也提供 內建函式 和內容 運算子 可評估的運算式更安全、更方便。這個主題也說明需要知道的下列的 C++ 運算式的限制:
您不能在程式碼、指令碼或 Managed 程式碼運算式中使用內容運算子或大多數的格式規範。這些都是原生 C++ 運算式評估工具所專用的。
本節內容
使用維護偵錯工具 intrinisic 函式的狀態
使用指定內容的運算子符號。
對原生 C++ 運算式的限制
存取控制
模稜兩可
匿名命名空間
建構函式、解構函式和轉換
繼承
Inlined 和編譯器內建函式
數值常數。
運算子函式
多載化
優先順序
符號格式
型別轉換
使用維護偵錯工具 intrinisic 函式的狀態
偵錯工具內建函式讓您可以在呼叫運算式的某些 C/C++ 函式,而不需要變更應用程式的狀態。
偵錯工具內建函式:
保證安全的:執行偵錯工具內建函式不會損毀偵錯的處理序。
在所有運算式允許,即使在副作用和函式評估不允許的案例。
工作在一般函式呼叫不是可能的案例,例如偵錯小型傾印。
偵錯工具內建函式也可以評估的運算式更加方便。例如, strncmp(str, “asd”) 與 str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’容易撰寫在中斷點條件。)
區域 |
內建函式 |
---|---|
字串長度。 |
strlen, wcslen, strnlen, wcsnlen |
字串比較 |
strcmp, wcscmp, stricmp, _stricmp, _strcmpi, wcsicmp, _wcscmpi, _wcsnicmp, strncmp, wcsncmp, strnicmp, wcsnicmp |
搜尋字串 |
strchr, wcschr, strstr, wcsstr |
Win32 |
GetLastError(), TlsGetValue() |
Windows 8 |
WindowsGetStringLen(), WindowsGetStringRawBuffer() 這些函式需要偵錯在 Windows 8 的流程。偵錯從 Windows 8 裝置產生的傾印檔案也需要 Visual Studio 電腦正在執行 Windows 8。不過,因此,如果是在遠端偵錯 Windows 8 裝置, Visual Studio 電腦上執行 Windows 7。 |
其他 |
__log2 傳回指定的整數的記錄 Base 2,捨入至最接近的整數。 |
使用指定內容的運算子符號。
內容運算子為原生的偵錯工具所提供的額外運算子。在偵錯機器碼,您可以使用內容運算子限定中斷點位置、變數名稱或運算式。內容運算子可用於指定外部範圍的名稱等用途,否則這些名稱將被區域的名稱所隱藏。
語法
{0},, [模組] 運算式}
模組 是模組的名稱。您可以使用完整路徑釐清具有相同名稱的模組之間。
運算式 是有效的目標的解析,例如一個函式名稱、變數名稱或指標位址在 模組中的任何有效的 C++ 運算式。
括號必須包含兩個逗號和模組 (可執行檔或 DLL) 名稱或完整路徑。
例如,將中斷點設定在 EXAMPLE.dll 的 SomeFunction 函式:
{,,EXAMPLE.dll}SomeFunction
如果 模組 路徑包括逗號、空白字元或一個括號,您必須在路徑前後加上引號,讓內容剖析器可以正確辨識字串。由於單引號被視為 Windows 檔案名稱的一部分,因此您必須使用雙引號。例如:
{,"a long, long, library name.dll", } g_Var
當運算式評估工具在運算式中碰到一個符號時,它將以下列順序來搜尋該符號:
向外擴展語彙範圍 (Lexical Scope),從目前的區塊開始,也就是大括號所括住的一系列陳述式,繼續向外擴展括住的區塊。目前的區塊為包含目前位置 (指令指標位址) 的程式碼。
函式範圍。目前的函式。
如果目前的位置是在 C++ 成員函式內,則為類別範圍 (Class Scope)。類別範圍包含所有的基底類別。運算式評估工具將使用一般的支配規則。
在目前模組的全域符號。
在目前程式的公用符號。
內容運算子,您可指定搜尋範圍開始的模組並略過目前的位置。
對原生 C++ 運算式的限制
當您將 C/C++ 運算式輸入至偵錯工具視窗時,將會套用下列一般性限制:
存取控制
偵錯工具可存取所有的類別成員,不管其存取控制為何。您可檢查任何的類別物件成員,包括了基底類別和內嵌的成員物件。
模稜兩可
如果偵錯工具運算式參考到模稜兩可的成員名稱,您必須使用類別名稱來限定它。例如,如果 CObject 是 CClass 的執行個體,並且它從 AClass 和 BClass 繼承了名為 expense 的成員函式,那麼 CObject.expense 就是模稜兩可的。您可透過下列方式來解決此語意模糊的問題:
CObject.BClass::expense
運算式評估工具針對成員名稱套用一般的支配規則以解決語意模糊的問題。
匿名命名空間
原生 C++ 運算式評估工具不支援匿名命名空間。假設,如果您有下列的程式碼:
#include "stdafx.h"
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
在此範例中,監看符號 test 的唯一方法,就是使用裝飾名稱 (Decorated Name):
(int*)?test@?A0xccd06570@mars@@3HA
建構函式、解構函式和轉換
您不能使用要求建構暫存物件的運算式來呼叫 (無論明確或隱含的呼叫) 物件的建構函式 (Constructor) 或解構函式 (Destructor)。例如,下列的運算式明確地呼叫一個建構函式,並產生錯誤訊息:
Date( 2, 3, 1985 )
您不能呼叫型別轉換函式 (Conversion Function),如果該轉換的目的型別為類別。這類轉換牽涉到物件的建構。例如,如果 myFraction 是 CFraction 的執行個體,而其定義了型別轉換函式運算子 FixedPoint,那麼下列的運算式將產生一個錯誤:
(FixedPoint)myFraction
不過,如果轉換的目的型別為內建資料型別,您就可以呼叫型別轉換函式。如果 CFraction 定義了轉換函式 operator float,下列運算式在偵錯工具中就是合法的:
(float)myFraction
您可以呼叫傳回物件或宣告區域物件 (Local Object) 的函式。
您不能呼叫 new 或 delete 運算子。下列運算式無法用於偵錯工具內:
new Date(2,3,1985)
繼承
當您使用偵錯工具來顯示具有虛擬 (Virtual) 基底類別的類別物件時,每個繼承路徑的虛擬基底類別成員都會顯示出來,即使這些成員只有一個執行個體被儲存。
虛擬函式呼叫會由運算式評估工具適當地處理。例如,假設 CEmployee 類別定義一個虛擬函式 computePay,而該虛擬函式又於繼承自 CEmployee 的類別中重新定義。您可透過指向 CEmployee 的指標來呼叫 computePay,並執行適當的函式:
empPtr->computePay()
您可將衍生類別 (Derived Class) 物件的指標轉換成基底類別物件的指標。當繼承是虛擬的,您可以將這個指標到基底類別物件的指標轉換為衍生類別物件,除了。
Inlined 和編譯器內建函式
除非函式至少一次會顯示為一般功能,偵錯工具運算式無法稱為編譯器內建函式或內嵌函式。
數值常數。
偵錯工具運算式可以使用八進位、十六進位或十進位格式的整數常數。根據預設,偵錯工具預期的是十進位常數。這個設定可以在 [偵錯] 索引標籤的 [一般] 頁面上變更。
您可使用前置或後置符號來代表採用另一種基底的數值。下表顯示了您可使用的形式。
語法 |
範例 (十進位 100) |
基底 |
---|---|---|
digits |
100 或 64 |
十進位或十六進位,視目前的設定而定。 |
0數字 |
0144 |
八進位 (基底 8) |
0n數字 |
0n100 |
十進位 (基底 10) |
0x數字 |
0x64 |
十六進位 (基底 16) |
數字h |
64h |
十六進位 (基底 16) |
運算子函式
偵錯工具運算式可針對類別,隱含或明確地叫用 (Invoke) 運算子函式。例如,假設 myFraction 和 yourFraction 為有定義 operator+ 之類別的執行個體。您可使用下列運算式來顯示這兩個物件的總和:
myFraction + yourFraction
如果運算子函式被定義成 friend 函式,則您可以使用成員函式所採用的相同語法隱含地呼叫它,或是明確地叫用它,如下所示:
operator+( myFraction, yourFraction )
和一般的函式一樣,呼叫運算子函式時所傳入的引數不能要求牽涉到物件建構的轉換。
偵錯工具不支援具有 Const 和非 Const 版本的多載運算子。具有 const 和非 const 版本的多載運算子經常用於 Standard Template Library 內。
多載化
如果有完全相符的函式存在,或有不需要牽涉到物件建構轉換的函式存在,偵錯工具運算式便可呼叫多載函式。例如,如果 calc 函式採用 CFraction 物件來做為參數,而 CFraction 類別定義了接受一個整數的單一引數建構函式,那麼下列的運算式將產生一個錯誤:
calc( 23 )
即使有一個合法的轉換可將該整數轉換成 calc 所期待的 CFraction 物件,但是這類轉換牽涉到物件的建立,而偵錯工具並沒有支援。
優先順序
在偵錯工具運算式中,C++ 範圍 (Scope) 運算子 (::) 的優先順序將比它在原始程式碼中來得低。在 C++ 的原始程式碼中,此運算子具有最高的優先順序。但在偵錯工具中,其優先順序落在基底和後置運算子 (->、++、--) 和一元 (Unary) 運算子 (!、&、* 及其他) 之間。
符號格式
您輸入的偵錯工具運算式,其所包含的符號採用了與原始程式碼相同的格式,假設符號都放在以完整偵錯資訊 (/Zi 或 /ZI) 編譯的模組內。如果您輸入一個包含公用符號的運算式,而這些符號位於程式庫或以 /Zd 編譯的模組內,則您必須使用符號的裝飾名稱 (Decorated Name),也就是目的碼 (Object Code) 中使用的格式。如需詳細資訊,請參閱 /Z7、/Zd、/Zi、/ZI (偵錯資訊格式)。
您可使用 LINK /MAP 選項,取得所有裝飾和未裝飾形式的名稱清單。如需詳細資訊,請參閱 /MAP (產生對應檔)。
名稱裝飾 (Name Decoration) 是用來強制型別安全連結的機制。這意味著只有具備完全相符的拼字、大小寫、呼叫慣例 (Calling Convention) 和型別的名稱和參考才會連結在一起。
以 C 呼叫慣例宣告的名稱,不論是隱含或明確地使用 _cdecl 關鍵字,都會以底線 (_) 開頭。例如,函式 main 可顯示成 _main。宣告成 _fastcall 的名稱則以 @ 符號開頭。
對於 C++ 而言,除了呼叫慣例外,還會將符號型別編入裝飾名稱。此種形式的名稱可能會很長,並且很難閱讀。名稱至少會以一個問號 (?) 開頭。對於 C++ 函式而言,裝飾將包含函式範圍、函式參數的型別以及函式的傳回型別 (Return Type)。
型別轉換
如果轉換為某個型別,則該型別必須是偵錯工具已知的型別。您的程式中必須有另一個該型別的物件。使用 typedef 陳述式 (Statement) 所建立的型別不受支援。