提示檔案
「提示檔案」包含巨集,可能會另外造成 C++ 瀏覽資料庫剖析器跳過程式碼區域。 當您開啟 Visual Studio C++ 專案時,剖析器會分析專案內每個原始程式檔中的程式碼,並建置含有每個識別碼之相關資訊的資料庫。 IDE 會使用該資訊來支援程式碼瀏覽功能,例如 [類別檢視] 瀏覽器和 [導覽列] 等功能。
C++ 瀏覽資料庫剖析器為模糊剖析器,可在短時間內剖析大量程式碼。 他速度快的其中一個原因是它會跳過區塊的內容。 比方說,它僅會記錄函式的位置及參數,並略過其內容。 某些巨集會導致用來判斷區塊起訖位置的啟發學習法發生問題。 而這些問題會造成不正確地記錄程式碼區域。
這些跳過的區域會以不同方式呈現:
[類別檢視]、[前往] 及 [導覽列] 中遺漏的類型及函式
[導覽列] 中的錯誤範圍
對已定義函式之 [建立宣告/定義] 的建議
提示檔案包含使用者可自訂的提示,其語法與 C/C++ 巨集定義相同。 Visual C++ 包含足夠供大部分專案使用的內建提示檔案。 不過,您可建立自己的提示檔案,來專門為您的專案改進剖析器。
重要
若您修改或新增提示檔案,則必須採取額外的步驟才能讓變更生效:
- 在 Visual Studio 2017 15.6 版之前的版本:針對所有變更,刪除方案中的 .sdf 檔案和/或VC.db檔案。
- 在 Visual Studio 2017 15.6 版和更新版本中:在新增提示檔案之後關閉並重新開啟方案。
案例
#define NOEXCEPT noexcept
void Function() NOEXCEPT
{
}
若沒有提示檔案,Function
就不會在 [類別檢視]、[前往] 或 [導覽列] 中顯示。 新增具有此巨集定義的提示檔案後,剖析器現在可了解及取代 NOEXCEPT
巨集,讓其能夠正確地剖析函式:
#define NOEXCEPT
造成干擾的巨集
中斷剖析器的巨集有兩種:
封裝會修飾函式之關鍵字的巨集
#define NOEXCEPT noexcept #define STDMETHODCALLTYPE __stdcall
對於這些類型的巨集,提示檔案中僅需要其巨集名稱:
#define NOEXCEPT #define STDMETHODCALLTYPE
包含不對稱括弧的巨集
#define BEGIN {
對於這些類型的巨集,提示檔案中需要同時有該巨集的名稱及其內容:
#define BEGIN {
編輯器支援
從 Visual Studio 2017 15.8 版起,皆包含可找出干擾性巨集的數個功能:
醒目提示區域內剖析器所跳過的巨集。
您可使用快速動作建立包含醒目提示巨集的提示檔案,如果有現有的提示檔案,也可將巨集新增到該提示檔案。
在執行其中一個快速動作後,剖析器就會重新剖析提示檔案所影響的檔案。
根據預設,會將問題巨集醒目提示為建議。 醒目提示可變更為更顯眼的樣式,例如紅色或綠色波浪線。 使用 [工具]>[選項]>[文字編輯器]>[C/C++]>[檢視] 下 [程式碼波浪線] 區段中的 [已跳過瀏覽區域中的巨集] 選項。
顯示瀏覽資料庫錯誤
[專案]>[顯示瀏覽資料庫錯誤] 功能表命令,會在 [錯誤清單] 中顯示無法剖析的所有區域。 此命令用來簡化建置初始提示檔案的過程。 不過,剖析器無法判斷錯誤是否為干擾性巨集所致,因此您必須評估每個錯誤。 執行 [顯示瀏覽資料庫錯誤] 命令,然後巡覽至各個錯誤,以在編輯器中載入受影響的檔案。 檔案載入後,若區域內有巨集,就會予以醒目提示。 您可叫用快速動作將其新增至提示檔案。 更新提示檔案後,就會自動更新錯誤清單。 或者,若您要手動修改提示檔案,可使用 [重新掃描解決方案] 命令來觸發更新。
架構
提示檔案與實體目錄相關,而非顯示於 [方案總管] 中的邏輯目錄。 您不必將提示檔案新增至專案,就能讓提示檔案生效。 剖析系統只有在剖析原始程式檔時,才會使用提示檔案。
每個提示檔案都會命名為 cpp.hint。 多個目錄可能包含一個提示檔案,但特定目錄中只能有一個提示檔案。
零或多個提示檔案都會影響您的專案。 如果沒有提示檔案,剖析系統會使用錯誤復原技術來忽略無法解讀的原始程式碼。 否則,剖析系統會使用下列策略來尋找及收集提示。
搜尋順序
剖析系統會依下列順序搜尋目錄中的提示檔案。
包含 Visual C++ 安裝套件的目錄 (vcpackages)。 此目錄包含描述常用系統檔案中符號的內建提示檔案,例如 windows.h。 因此,您的專案會自動繼承所需的大部分提示。
從原始程式檔根目錄到包含原始程式檔本身之目錄的路徑。 在一般 Visual Studio C++ 專案中,根目錄會包含方案或專案檔。
此規則的例外是,如果「停止檔案」位於原始程式檔的路徑中。 停止檔案是任何名為 cpp.stop 的檔案。 停止檔案可讓您進一步控制搜尋順序。 剖析系統會搜尋包含停止檔案的目錄到包含原始程式檔的目錄,而不需要從根目錄開始。 在一般專案中,您不需要停止檔案。
提示收集
一個提示檔案包含零或多個「提示」。 如同 C/C++ 巨集,您可以定義或刪除提示。 也就是說,#define
前置處理器指示詞會建立或重新定義提示,而 #undef
指示詞會刪除提示。
剖析系統會以上述的搜尋順序開啟各提示檔案。 其會將每個檔案的提示累積成一組「有效提示」,然後使用該有效提示解譯您程式碼中的識別項。
剖析系統會使用這些規則來累積提示:
如果新提示指定尚未定義的名稱,則新提示會將該名稱新增至有效提示。
如果新提示指定已定義的名稱,新提示會重新定義現有的提示。
如果新提示是指定現有有效提示的
#undef
指示詞,新提示會刪除現有的提示。
第一項規則表示有效提示繼承自先前開啟的提示檔案。 後兩項規則表示在搜尋順序後面的提示,可以覆寫前面的提示。 例如,如果您在包含原始程式檔的目錄中建立提示檔案,您可以覆寫任何先前的提示。
如需如何收集提示的描述,請參閱範例一節。
語法
您用來建立及刪除提示的語法,與前置處理器指示詞用來建立及刪除巨集的語法相同。 事實上,剖析系統會使用 C/C++ 前置處理器來評估提示。 如需前置處理器指示詞的詳細資訊,請參閱 #define 指示詞 (C/C++) 和 #undef 指示詞 (C/C++)。
唯一不尋常的語法項目是 @<
、@=
和 @>
取代字串。 這些提示檔案專用的取代字串僅能在「對應」巨集中使用。 對應是將資料、函式或事件關聯到其他資料、函式或事件處理常式的一組巨集。 例如,MFC
使用對應來建立訊息對應,而 ATL
使用對應來建立物件對應。 提示檔案專用的取代字串會標記對應的開始、中間和結束元素。 唯一重要的是對應巨集的名稱。 因此,每個取代字串會刻意隱藏巨集的實作。
提示會使用此語法:
語法 | 意義 |
---|---|
#define hint-name replacement-string#define hint-name ( parameter, ...) replacement-string |
定義新提示或重新定義現有提示的前置處理器指示詞。 在指示詞後面,前置處理器會將原始程式碼中出現的每個 hint-name 取代成 replacement-string。 第二個語法形式會定義類似函式的提示。 如果原始程式碼中出現類似函式的提示,前置處理器會先將 replacement-string 中出現的每個 parameter 取代成原始程式碼中的對應引數,再將 hint-name 取代成 replacement-string。 |
@< |
提示檔案特定的 replacement-string,表示一組對應項目的開頭。 |
@= |
提示檔案特定的 replacement-string,表示中間對應項目。 一個對應可以有多個對應項目。 |
@> |
提示檔案特定的 replacement-string,表示一組對應項目的結尾。 |
#undef hint-name |
刪除現有提示的前置處理器指示詞。 提示的名稱是由 hint-name 識別項提供。 |
// 評論 |
單行註解。 |
/* 評論 */ |
多行註解。 |
範例
此範例說明如何從提示檔案累積提示。 此範例不會使用停止檔案。
此圖說明 Visual Studio C++ 專案中的一些實體目錄。 提示檔案位於 vcpackages
、Debug
、A1
和 A2
目錄。
提示檔案目錄
目錄和提示檔案內容
這個清單顯示此專案中包含提示檔案的目錄,以及這些提示檔案的內容。 僅列出 vcpackages
目錄提示檔案中,許多提示的一部分:
vcpackages
// vcpackages (partial list) #define _In_ #define _In_opt_ #define _In_z_ #define _In_opt_z_ #define _In_count_(size)
偵錯
// Debug #undef _In_ #define OBRACE { #define CBRACE } #define RAISE_EXCEPTION(x) throw (x) #define START_NAMESPACE namespace MyProject { #define END_NAMESPACE }
A1
// A1 #define START_NAMESPACE namespace A1Namespace {
A2
// A2 #undef OBRACE #undef CBRACE
有效提示
此表列出這個專案中來源檔案的有效提示:
原始程式檔:A1_A2_B.cpp
有效提示:
// vcpackages (partial list) #define _In_opt_ #define _In_z_ #define _In_opt_z_ #define _In_count_(size) // Debug... #define RAISE_EXCEPTION(x) throw (x) // A1 #define START_NAMESPACE namespace A1Namespace { // ...Debug #define END_NAMESPACE }
這些注意事項適用於上述清單:
有效提示來自於
vcpackages
、Debug
、A1
和A2
目錄。Debug
提示檔案中的 #undef 指示詞已移除vcpackages
目錄提示檔案中的#define _In_
提示。A1
目錄中的提示檔案會重新定義START_NAMESPACE
。A2
目錄中的#undef
提示已移除Debug
目錄提示檔案中的OBRACE
和CBRACE
提示。
另請參閱
為 Visual Studio C++ 專案建立的檔案類型
#define 指示詞 (C/C++)
#undef 指示詞 (C/C++)
SAL 註釋