__clrcall

指定只能从托管代码调用的函数。 对所有只能从托管代码调用的虚函数使用 __clrcall。 但是,此调用约定不能用于从本机代码调用的函数。 __clrcall 修饰符是 Microsoft 专用的。

当通过指针从托管函数调用到虚拟托管函数或从托管函数调用到托管函数时,可使用 __clrcall 来提高性能。

入口点是编译器生成的单独函数。 如果函数同时具有本机和托管入口点,则其中一个将是具有函数实现的实际函数。 其他函数将是调用到实际函数的单独函数(形式转换 (thunk))并允许公共语言运行时执行 PInvoke。 将函数标记为 __clrcall 时,可指示函数实现必须是 MSIL,并且不生成本机入口点函数。

当采用本机函数的地址时,如果未指定 __clrcall,编译器将使用本机入口点。 __clrcall 指示函数为托管函数,并且不需要经历从托管到本机的转换。 在这种情况下,编译器将使用托管入口点。

当使用了 /clr(不是 /clr:pure/clr:safe)而未使用 __clrcall 时,采用函数的地址将始终返回本机入口点函数的地址。 当使用了 __clrcall 时,不会创建本机入口点函数,因此你将获得托管函数的地址,而不是入口点形式转换函数的地址。 有关详细信息,请参阅双重形式转换。 “/clr:pure”和“/clr:safe”编译器选项在 Visual Studio 2015 中已弃用,并且在 Visual Studio 2017 中不受支持

/clr(公共语言运行时编译)表示所有函数和函数指针都是 __clrcall,并且编译器不允许将编译单位中的函数标记为 __clrcall 之外的任何内容。 使用 /clr:pure 时,只能在函数指针和外部声明上指定 __clrcall。

可直接从使用 /clr 编译的现有 C++ 代码调用 __clrcall 函数(只要该函数具有 MSIL 实现)。 例如,无法直接从具有内联 asm 的函数调用 __clrcall 函数,并且无法调用特定于 CPU 的内部函数,即使这些函数是使用 /clr 编译的。

__clrcall 函数指针仅能在创建它们的应用程序域中使用。 不要跨应用程序域传递 __clrcall 函数指针,而应使用 CrossAppDomainDelegate 有关详细信息,请参阅应用程序域和 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

以下示例显示,你可以定义函数指针以便将该函数指针声明为仅从托管代码调用。 这样,编译器便能直接调用托管函数并避免本机入口点(双形式转换 (thunk) 问题)。

// clrcall3.cpp
// compile with: /clr
void Test() {
   System::Console::WriteLine("in Test");
}

int main() {
   void (*pTest)() = &Test;
   (*pTest)();

   void (__clrcall *pTest2)() = &Test;
   (*pTest2)();
}

另请参阅

自变量传递和命名约定
关键字