程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#調用C++

C#調用C++

編輯:C#入門知識

最近搞了個小程序需要用到FFT,可是找來找去都沒有一種C#下可靠地FFT代碼,而且速度也不能令人滿意。發現MIT做過一個很好的C++類庫(http://www.fftw.org/)可以比較好的解決FFT的問題而且運算速度號稱世界最快的(雖然未經驗證,不過的確很快)。於是研究起在C#中調用C++的dll。
1. 在 C#中調用C++首先要包裝,將C++中的方法包裝成C#下的方法,下面這個不是我寫的,但過程都是這個,"libfftw3-3.dll" 文件名,"fftw_malloc"c++函數名,其他參數可以參照VS的幫助選擇。記得 using System.Runtime.InteropServices ,包裝後的方法必須是靜態的,至於如何使用靜態函數就不用多說了吧。
 1 /// <summary>
 2 /// Contains the Basic Interface FFTW functions for double-precision (double) operations
 3 /// </summary>
 4 public class FFT
 5 {
 6   /// <summary>
 7   /// Allocates FFTW-optimized unmanaged memory
 8   /// </summary>
 9   /// <param name="length">Amount to allocate, in bytes</param>
10   /// <returns>Pointer to allocated memory</returns>
11   [DllImport("libfftw3-3.dll",
12   EntryPoint = "fftw_malloc",
13   ExactSpelling = true,
14   CallingConvention = CallingConvention.Cdecl)]
15   public static extern IntPtr malloc(int length);
16 }
 
 
2,緊接著關鍵的問題來了,參數怎麼設置?C++大量使用指針而在C#中沒有指針。別急,看到上面個例子中的和函數返回值 IntPtr (using System)了嗎?其實這個就是C#中的地址數據類型。調用中簡單數據類型(如 int等)都可以直接使用的,少數(如string)要特殊處理都很容易,對於復雜的數據類型(類,數組...)就要用到這個 IntPtr 了。
   對於C++出現任何類型的指針在C#中都用 IntPtr 代替,但是如何使用呢?這裡還涉及到一個代理 GCHandle (using System.Runtime.InteropServices)他可以幫我們在地址和對象之間進行轉換,我舉個例子。
1 IntPtr plan;
2
3 double[] fin = new double[nx * ny * 2];
4 GCHandle hin = GCHandle.Alloc(fin, GCHandleType.Pinned);
5
6 plan = FFT.dft_2d(nx, ny, hin.AddrOfPinnedObject(), hin.AddrOfPinnedObject(), fftw_direction.Forward, fftw_flags.Estimate);
  dft_2d 原型:後面兩個參數是枚舉類型
1 public static extern IntPtr dft_2d(int nx, int ny, IntPtr input, IntPtr output, fftw_direction direction, fftw_flags flags);
 
 FFT.dft_2d 就是封裝好的目標函數,我們就是要調用這個函數。fin是一個復雜對象,hin是我們的代理,Alloc操作就是將對象和內存綁定起來交給系統代理。hin.AddrOfPinnedObject()就是fin對應的地址(IntPtr類型)我們把它當做指針傳給C++,這樣C++會調用fin數據同時如果C++在函數內修改了hin代理的數據C#這邊的數據也會隨之變化,用C++的人很熟悉這種通過傳入指針獲得輸出結果的方式吧。GCHandle 還有一個重要的屬性Target,C#中可以直接通過這個屬性獲得代理的對象,這樣我們就可以把對象換指針也可以把指針換成對象。
   簡單說就是1.通過 GCHandle hin = GCHandle.Alloc(fin, GCHandleType.Pinned)綁定對象後通過hin.AddrOfPinnedObject()獲得IntPtr型的地址給C++用
                 2.通過 hin.Target 獲得對象給C#用
    注意:1.Alloc已經將對象綁定到內存了,如果之後再修改 fin 的對象 比如在第五行加入 fin = new double[2]對hin是無影響的,所以賦值操作一定要在Alloc之前執行。記得要為被綁定的對象賦初值,不然C++會報空指針的(new 一下不是很累吧!)。
 
 
 3 是不是很簡單,不過我還是要在多說幾句。既然用了C++和代理那麼不要忘記釋放內存哦,這點C#程序員很容易搞忘了。C++類庫一般提供釋放方法,GCHandle有Free()函數,謹記之!!!
 

 

摘自 Ghost_zhao

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved