首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Managed C++ 函數呼叫雙重入口點與 __clrcall 效能優化

     編輯:VC 教學

問題由來

/clr 編譯時,受控函數會產生兩個入口點:

  • 受控入口:供受控碼呼叫,參數/回傳為受控型別。
  • 非受控入口:供原生碼透過函數指標呼叫,參數封送為原生表示。

虛函數指標只能指向其中一個,編譯器需選擇預設入口。VS2003 一律選非受控;VS2005+ 若簽章含受控型別則選受控入口。跨入口呼叫會觸發受控/非受控轉換與參數複製,影響效能。

解決方案:__clrcall

在函數宣告加上 __clrcall,指示編譯器僅產生受控入口,消除雙重入口與轉換開銷。限制:該函數不可被非受控碼透過函數指標呼叫。

效能實測:氣泡排序

using namespace System;
#define ARRAY_SIZE 1000

struct bubbleBase { int value; };

class bubble1 : public bubbleBase {
public:
    virtual int getvalue() { return value; }
    virtual void setvalue(int nv) { value = nv; }
};

class bubble2 : public bubbleBase {
public:
    virtual int __clrcall getvalue() { return value; }
    virtual void __clrcall setvalue(int nv) { value = nv; }
};

template void bubbleSort(int length) {
    TimeSpan ts;
    T* array1 = new T[ARRAY_SIZE];
    for (int i=0; i0; --i) {
        int test=0;
        for (int j=0; j array1[j+1].getvalue()) {
                int temp = array1[j].getvalue();
                array1[j].setvalue(array1[j+1].getvalue());
                array1[j+1].setvalue(temp);
                test=1;
            }
        }
        if (!test) break;
    }
    ts = TimeSpan::FromTicks(DateTime::Now.Ticks - ticks);
    Console::WriteLine("BubbleSort {0} Items: {1} Ticks", ARRAY_SIZE, ts.Ticks);
    delete[] array1;
}

int main(array^ args) {
    bubbleSort(ARRAY_SIZE); // 無 __clrcall
    bubbleSort(ARRAY_SIZE); // 有 __clrcall
    return 0;
}

執行結果

BubbleSort 1000 Items: 3281250 Ticks   // bubble1
BubbleSort 1000 Items: 312500 Ticks    // bubble2

加速約 10.5 倍。頻繁呼叫的虛函數、介面方法、委派目標均適用。

補充:STL 安全檢查關閉

VC8.0 STL 預設啟用 _SECURE_SCL(迭代器邊界檢查),確認無緩衝區溢位風險時,定義 _SECURE_SCL=0 可進一步提升速度。

適用判斷清單

  • [ ] 函數僅在受控碼內部呼叫。
  • [ ] 不需對外匯出供原生 DLL 透過函數指標使用。
  • [ ] 為熱點路徑(高頻呼叫、虛函數、介面實作)。
  • [ ] 簽章含受控型別(^, %, generic 等)。

滿足上述條件即可放心加上 __clrcall 獲取效能紅利。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved