__clrcall
Microsoft 固有の仕様 →
関数はマネージ コードから呼び出すことができることを指定します。使用__clrcallをマネージ コードからのみ呼び出されるすべての仮想関数します。しかしこの呼び出し規約は、ネイティブ コードから呼び出される関数は使用できません。
使用__clrcallから、マネージ関数を仮想マネージ関数またはマネージ関数へのポインターをマネージ関数から呼び出すときのパフォーマンスを向上させる。
エントリ ポイントは、独立した、コンパイラによって生成された関数です。両方のネイティブおよびマネージ エントリ ポイント関数を持つ場合は、それらのいずれかの実際の関数と関数の実装ができます。その他の関数に実際の関数を呼び出すと、共通言語ランタイムを PInvoke を実行することができます、別の関数 (サンク) になります。関数としてマークするとき__clrcall、関数の実装が MSIL でなければなりませんし、ネイティブ エントリ ポイント関数は生成されませんを示します。
場合は、ネイティブ関数のアドレスを実行時__clrcallを指定しない、コンパイラはネイティブ エントリ ポイントを使用します。__clrcall関数の管理はネイティブへからの移行が必要になる管理されないことを示します。この場合、コンパイラはマネージ エントリ ポイントを使用します。
/clr (ない**/clr:pureまたは/clr:safe**) を使用し、 __clrcallです使用ではなく、常に関数のアドレスを取得、ネイティブ エントリ ポイント関数のアドレスを返します。時__clrcallがエントリ ポイント サンク関数できません、マネージ関数のアドレスを取得するため、ネイティブ エントリ ポイント関数は作成されません。詳細については、「ダブル サンキング (C++)」を参照してください。
/clr (共通言語ランタイムのコンパイル)すべての関数と関数ポインターであることを意味__clrcall 、コンパイラは、関数の中何も以外にマークするのには、コンパイルできません。 __clrcall。時**/clr:pure** 、 __clrcall関数ポインターと外部の宣言でのみ指定できます。
直接呼び出すことができます__clrcall関数を使用してコンパイルされた既存の C++ コードから**/clr**その関数が MSIL の実装を持つ限り、します。__clrcall関数呼び出すことができませんインライン asm を持ち、CPU に固有の intrinisics を呼び出す関数から直接これらの関数をコンパイルされている場合でも、 /clr。
__clrcall関数ポインターのみが作成されたアプリケーション ドメインで使用する目的としています。引き渡しではなく__clrcallポインターをアプリケーション ドメインにわたって機能、使用CrossAppDomainDelegate。詳細については、「アプリケーション ドメインと Visual C++」を参照してください。
使用例
// clrcall.cpp
// compile with: /clr:oldSyntax /LD
void __clrcall Test1( ) {}
void (__clrcall *fpTest1)( ) = &Test1;
関数が宣言されている場合に、注意してください__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();
}
関数ポインターは、マネージ コードから呼び出されることを宣言するように、次の例では、関数のポインターを定義できることを示します。これは、マネージ関数を直接呼び出すし、ネイティブ エントリ ポイント (二重サンク問題) を回避するには、コンパイラをできます。
// clrcall3.cpp
// compile with: /clr
void Test() {
System::Console::WriteLine("in Test");
}
int main() {
void (*pTest)() = &Test;
(*pTest)();
void (__clrcall *pTest2)() = &Test;
(*pTest2)();
}