zoukankan      html  css  js  c++  java
  • 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()函数,谨记之!!!

       祝各位,学习进步,工作愉快,身体健康!

  • 相关阅读:
    Python 内置数据结构之 set
    python 在指定的文件夹下生成随机的测验试卷文件
    Python 的 import 语句
    Python 和 R 中的一数多图
    Python 语法练习题
    python 3.x 和 2.x 不同
    R 的 plyr 包
    Python 和 R语言 中的折线图
    设置 Jupyter notebook 默认路径、启动快捷键、打开浏览器
    Python 虚拟环境
  • 原文地址:https://www.cnblogs.com/GhostZCH/p/2437675.html
Copyright © 2011-2022 走看看