__clrcall
指定函式只可以從 Managed 程式碼呼叫。 針對只會從 Managed 程式碼呼叫的所有虛擬函式,請使用 __clrcall 。 不過,這個呼叫慣例不能用於將會從機器碼呼叫的函式。 __clrcall 修飾詞是 Microsoft 特定的。
使用 __clrcall 來改善從 Managed 函式呼叫虛擬 Managed 函式或透過指標從 Managed 函式到 Managed 函式時的效能。
進入點是編譯器產生的不同函式。 如果函式同時具有原生和 Managed 進入點,則其中一個會是具有函式實作的實際函式。 另一個函式將會是呼叫實際函式內部的另一個函式 (Thunk),並且會讓 Common Language Runtime 執行 PInvoke。 將函式 標示為 __clrcall時,表示函式實作必須是 MSIL,而且不會產生原生進入點函式。
如果未 指定__clrcall ,則取得原生函式的位址時,編譯器會使用原生進入點。 __clrcall表示函式已受到管理,而且不需要進行從 Managed 轉換到原生的轉換。 在這種情況下,編譯器會使用 Managed 進入點。
使用 /clr
(不是 /clr:pure
或 /clr:safe
) 且 未使用__clrcall 時,取用函式的位址一律會傳回原生進入點函式的位址。 使用__clrcall 時 ,不會建立原生進入點函式,因此您會取得 Managed 函式的位址,而不是進入點 Thunk 函式。 如需詳細資訊,請參閱 Double Thunking 。 Visual Studio 2015 中已淘汰 /clr:pure 和 /clr:safe 編譯器選項,且 Visual Studio 2017 不支援。
/clr (Common Language Runtime 編譯) 表示所有函式和函式指標都會 __clrcall,編譯器不允許編譯器內的函式,而且除了__clrcall 之外 ,也不會標記任何函式。 使用 /clr:pure 時 , __clrcall 只能在函式指標和外部宣告上指定。
只要該函式具有 MSIL 實作,您就可以直接從使用 /clr 編譯的現有 C++ 程式碼呼叫 __clrcall 函式。 __clrcall函式無法直接從具有內嵌 asm 且呼叫 CPU 特定內建函式的函式呼叫,例如,即使這些函式是以 /clr
編譯。
__clrcall函式指標只用于建立它們的應用程式域中。 使用 ,而不是跨應用程式域 CrossAppDomainDelegate 傳遞 __clrcall 函式指標。 如需詳細資訊,請參閱 應用程式域和 Visual C++ 。
範例
請注意,當以 __clrcall 宣告 函式 時,將會視需要產生程式碼;例如,呼叫函式時。
// clrcall2.cpp
// compile with: /clr
using namespace System;
int __clrcall Func1() {
Console::WriteLine("in Func1");
return 0;
}
// Func1 hasn't been used at this point (code has not been generated),
// so runtime returns the adddress of a stub to the function
int (__clrcall *pf)() = &Func1;
// code calls the function, code generated at difference address
int i = pf(); // comment this line and comparison will pass
int main() {
if (&Func1 == pf)
Console::WriteLine("&Func1 == pf, comparison succeeds");
else
Console::WriteLine("&Func1 != pf, comparison fails");
// even though comparison fails, stub and function call are correct
pf();
Func1();
}
in Func1
&Func1 != pf, comparison fails
in Func1
in Func1
下列範例說明您可以定義函式指標,這樣就表示您宣告函式指標只能從 Managed 程式碼叫用。 如此編譯器就能夠直接呼叫 Managed 函式,並且避開原生進入點 (雙 Thunk 問題)。
// clrcall3.cpp
// compile with: /clr
void Test() {
System::Console::WriteLine("in Test");
}
int main() {
void (*pTest)() = &Test;
(*pTest)();
void (__clrcall *pTest2)() = &Test;
(*pTest2)();
}