原生 C++ 中的運算式
偵錯工具可接受大部分的 Microsoft 和 ANSI C/C++ 運算式。 偵錯工具也提供「內建函式」(Intrinsic Function) 和「內容運算子」(Context Operator),可讓評估運算式更安全、更方便。 本主題同時描述以下需要注意之 C++ 運算式的限制:
您不能在程式碼、指令碼或 Managed 程式碼運算式中使用內容運算子或大多數的格式規範。 這些都是原生 C++ 運算式評估工具所專用的。
本節內容
使用偵錯工具內建函式維持狀態
使用內容運算子指定符號
原生 C++ 運算式的限制
存取控制
模稜兩可的參考
匿名命名空間
建構函式、解構函式和轉換
繼承
內嵌函式和編譯器內建函式
數值常數
運算子函式
多載化
優先順序
符號格式
型別轉換
使用偵錯工具內建函式維持狀態
偵錯工具內建函式可讓您呼叫運算式中的某些 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 傳回所指定整數的對數底數 2,並捨入至最接近的較小整數。 |
使用內容運算子指定符號
內容運算子為原生偵錯工具所提供的額外運算子。 對機器碼進行偵錯時,您可以使用內容運算子限定中斷點位置、變數名稱或運算式。 內容運算子對於指定來自外部範圍的名稱等用途相當實用,因為這類名稱會被本機名稱所隱藏。
語法
{,,[module] } expression
module 是模組的名稱。 您可以使用完整路徑釐清具有相同名稱的模組。
expression 是解析為有效目標的任何有效 C++ 運算式,例如 module 中的函式名稱、變數名稱或指標位址。
大括號必須包含兩個逗號和模組 (可執行檔或 DLL) 名稱或完整路徑。
例如,若要在 EXAMPLE.dll 的 SomeFunction 函式處設定中斷點:
{,,EXAMPLE.dll}SomeFunction
如果 module 路徑包含逗號、內嵌空格或大括號,您就必須使用引號括住路徑,如此內容剖析器才能正確辨識字串。 單引號會視為 Windows 檔案名稱的一部分,因此您必須使用雙引號。 例如:
{,"a long, long, library name.dll", } g_Var
當運算式評估工具在運算式中遇到符號時,它會依照下列順序搜尋該符號:
語彙範圍向外擴展,從目前區塊開始 (大括號括住的一連串陳述式),並繼續向外擴展至封閉區塊。 目前區塊是包含目前位置 (指令指標位址) 的程式碼。
函式範圍。 目前函式。
類別範圍 (如果目前位置是在 C++ 成員函式內)。 類別範圍包括所有基底類別。 運算式評估工具將使用一般支配規則。
目前模組中的全域符號。
目前程式中的公用符號。
使用內容運算子可以指定搜尋的起始模組,並跳過目前位置。
原生 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 的唯一方法,就是使用裝飾名稱:
(int*)?test@?A0xccd06570@mars@@3HA
建構函式、解構函式和轉換
您無法使用呼叫建構暫存物件的運算式,明確或隱含呼叫物件的建構函式或解構函式。 例如,下列運算式會明確呼叫建構函式,並產生錯誤訊息:
Date( 2, 3, 1985 )
如果轉換的目的地是類別,您就無法呼叫轉換函式。 這類轉換牽涉到物件的建構。 例如,如果 myFraction 是 CFraction 的執行個體,它負責定義轉換函式運算子 FixedPoint,那麼下列運算式將會產生錯誤:
(FixedPoint)myFraction
不過,如果轉換的目的地是內建類型,您就可以呼叫轉換函式。 如果 CFraction 定義了轉換函式 operator float,則下列運算式在偵錯工具中會是合法的:
(float)myFraction
您可以呼叫傳回物件或宣告本機物件的函式。
您無法呼叫 new 或 delete 運算子。 下列運算式不適用於偵錯工具:
new Date(2,3,1985)
繼承
當您使用偵錯工具顯示具有虛擬基底類別的類別物件時,會顯示每個繼承路徑的虛擬基底類別成員 (即使只有儲存其中一個這些成員的執行個體)。
運算式評估工具可正確處理虛擬函式呼叫。 例如,假設 CEmployee 類別定義了虛擬函式 computePay,而該虛擬函式又在繼承自 CEmployee 的類別中重新定義。 您可以透過 CEmployee 的指標呼叫 computePay,並執行適當的函式:
empPtr->computePay()
您可以將衍生類別物件的指標轉型成基底類別物件的指標。 您可以將基底類別物件的指標轉型成衍生類別物件的指標,但繼承為虛擬時例外。
內嵌函式和編譯器內建函式
除非函式至少做為正常函式出現一次,否則偵錯工具運算式無法呼叫編譯器內建函式或內嵌函式。
數值常數
偵錯工具運算式可以使用八進位、十六進位或十進位格式的整數常數。 根據預設,偵錯工具預期的是十進位常數。 這項設定可以在 [偵錯] 索引標籤的 [一般] 頁面上變更。
您可以使用前置或後置符號代表採用另一種基底的數值。 下表將說明您可以使用的形式。
語法 |
範例 (十進位 100) |
基底 |
---|---|---|
digits |
100 或 64 |
十進位或十六進位,視目前的設定而定。 |
0 digits |
0144 |
八進位 (基底 8) |
0n digits |
0n100 |
十進位 (基底 10) |
0x digits |
0x64 |
十六進位 (基底 16) |
digits h |
64h |
十六進位 (基底 16) |
運算子函式
偵錯工具運算式可針對類別,隱含或明確地叫用運算子函式。 例如,假設 myFraction 和 yourFraction 負責定義 operator+ 之類別的執行個體。 您可以使用下列運算式顯示這兩個物件的總和:
myFraction + yourFraction
如果運算子函式定義為 friend,則您可以使用與成員函式相同的語法隱含呼叫它,或是明確叫用它,如下所示:
operator+( myFraction, yourFraction )
和一般函式一樣,呼叫運算子函式時,不能使用需要牽涉到物件建構之轉換的引數。
偵錯工具不支援同時具有 const 和非 const 版本的多載運算子。 具有 const 和非 const 版本的多載運算子經常用於「標準範本庫」(Standard Template Library) 內。
多載化
如果有完全相符項目存在,或是有不需要牽涉到物件建構之轉換的項目存在,偵錯工具運算式就可以呼叫多載函式。 例如,如果 calc 函式接受 CFraction 物件做為參數,而 CFraction 類別定義了接受整數的單一引數建構函式,那麼下列運算式將會產生錯誤:
calc( 23 )
即使有合法的轉換可將該整數轉換成 calc 期待的 CFraction 物件,但是這類轉換牽涉到建立物件,因此不支援。
優先順序
在偵錯工具運算式中,C++ 範圍運算子 (::) 的優先順序比它在原始程式碼中來得低。 在 C++ 原始程式碼中,這個運算子具有最高優先順序。 但在偵錯工具中,它的優先順序落在基底和後置運算子 (->、++、--) 與一元運算子 (!、&、* 等) 之間。
符號格式
您輸入的偵錯工具運算式包含的符號採用與原始程式碼中相同的格式 (假設符號都在以完整偵錯資訊 (/Zi 或 /ZI) 編譯的模組內)。 如果您輸入包含公用符號的運算式,而這些符號位於程式庫或以 /Zd 編譯的模組內,則您必須使用符號的裝飾名稱,也就是目的碼中使用的格式。 如需詳細資訊,請參閱 /Z7、/Zd、/Zi、/ZI (偵錯資訊格式)。
您可以使用 LINK /MAP 選項,取得所有裝飾和未裝飾形式的名稱清單。 如需詳細資訊,請參閱 /MAP (產生對應檔)。
名稱裝飾是用來強制執行類型安全連結的機制。 這表示,只有具備完全相符的拼字、大小寫、呼叫慣例和類型的名稱和參考才會連結在一起。
使用 _cdecl 關鍵字以 C 呼叫慣例隱含或明確宣告的名稱,都會以底線 (_) 開頭。 例如,函式 main 可以顯示為 _main。 宣告為 _fastcall 的名稱會以 @ 符號開頭。
對於 C++ 而言,除了呼叫慣例外,裝飾名稱還會將符號的類型編碼。 這種形式的名稱可能會很長,並且很難閱讀。 名稱至少會以一個問號 (?) 開頭。 對於 C++ 函式而言,裝飾包含函式範圍、函式參數的類型,以及函式傳回類型。
型別轉換
如果您轉型為某個類型,則該類型必須是偵錯工具已知的類型。 您的程式中必須有另一個該類型的物件。 不支援使用 typedef 陳述式建立的類型。