__clrcall

Указывает, что функцию можно вызвать только из управляемого кода. Используйте __clrcall для всех виртуальных функций, которые будут вызываться только из управляемого кода. Однако это соглашение о вызовах невозможно использовать для функций, которые будут вызываться из машинного кода. Модификатор __clrcall относится к Корпорации Майкрософт.

Используйте __clrcall для повышения производительности при вызове из управляемой функции в виртуальную управляемую функцию или из управляемой функции в управляемую функцию с помощью указателя.

Точки входа представляют собой отдельные функции, создаваемые компилятором. Если функция имеет машинные и управляемые точки входа, одна из них будет фактической функцией с реализацией функции. Другая функция будет отдельной функцией (преобразователем), которая вызывает фактическую функцию и позволяет среде CLR выполнять PInvoke. При маркировке функции как __clrcall необходимо указать, что реализация функции должна быть MSIL и что собственная функция точки входа не будет создана.

При получении адреса собственной функции, если __clrcall не указан, компилятор использует собственную точку входа. __clrcall указывает, что функция управляется, и нет необходимости проходить переход от управляемого к собственному. В этом случае компилятор использует управляемую точку входа.

Если /clr используется (не /clr:pure или /clr:safe) и __clrcall не используется, принимая адрес функции всегда возвращает адрес собственной функции точки входа. При использовании __clrcall функция собственной точки входа не создается, поэтому вы получите адрес управляемой функции, а не функцию точки входа. Дополнительные сведения см. в разделе Double Thunking. Параметры компилятора /clr:pure и /clr:safe компилятора устарели в Visual Studio 2015 и не поддерживаются в Visual Studio 2017.

/clr (компиляция среды clr) подразумевает, что все функции и указатели функций __clrcall, и компилятор не позволит функции внутри компилятора пометить что-либо, отличное от __clrcall. Если используется параметр /clr:pure , __clrcall можно указать только в указателях функций и внешних объявлениях.

Вы можете напрямую вызывать функции __clrcall из существующего кода C++, скомпилированного с помощью /clr , если эта функция имеет реализацию MSIL. __clrcall функции нельзя вызывать непосредственно из функций, имеющих встроенные функции asm и вызывающие встроенные функции ЦП, например, даже если эти функции компилируются с /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

В следующем примере показано, что можно определить указатель функции, например объявить, что указатель функции будет вызываться только из управляемого кода. Это позволит компилятору непосредственно вызвать управляемую функцию и избежать машинной точки входа (проблема двойного преобразования).

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

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

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

См. также

Передача аргументов и соглашения об именовании
Ключевые слова