指针上的C#指针

本文关键字:指针 | 更新日期: 2023-09-27 18:29:53

我以前从未使用过指针,现在我需要使用,即使我已经读过它们,我仍然不知道如何使用它们!我使用的是第三方产品(Mitov Signal Lab),我使用的控件具有允许我截获数据的事件。当我输入事件时,我可以访问"args",其中一条语句将返回一个指针。现在,它指向一个4096个双值的缓冲区(一个是实数,下一个是虚数等)。这就是代码:

 private void genericComplex1_ProcessData(object Sender, Mitov.SignalLab.ProcessComplexNotifyArgs Args)
    {
        unsafe
        {
         IntPtr pointer =  Args.InBuffer.Read(); 
         // now what????  I want to get each double value, do some calculations on them
         // and return them to the buffer.
         }
      args.sendOutPutData = true;
   }

我假设我需要将指针分配给Args.InBuffer.Read()但我试过一些我见过的例子,但我只是犯了错误。我使用的是visualstudio2010,我正在使用/unsafe进行编译。这是最新消息。还有其他方法,如Args.Inbuffer.Write()和Args.Inbuffer.Modify(),但我仍然不知道如何访问缓冲区的各个组件。

好的,这里有更多的细节。我用的是马歇尔复印件。这是代码:

   private void genericComplex1_ProcessData(object Sender, Mitov.SignalLab.ProcessComplexNotifyArgs Args)
    {
        //used to generate a phase corrected Q signal
        //equations:
        // real = real
        // imaginary = (1 + amplitudeimbalance)(real*cos(phaseImbalance) + imaginary*sin(phaseImbalance)
        //but amplitude imbalance is already corrected therefore
        //imaginary = real * cos(phaseCorrection) + imaginary*sin(phaseCorrection)
        double real;
        double imaginary;
        double newImaginary;
        var bufferSize = Convert.ToInt32(Args.InBuffer.GetSize());
        Mitov.SignalLab.ComplexBuffer ComplexDataBuffer = new Mitov.SignalLab.ComplexBuffer(bufferSize);
        ComplexDataBuffer.Zero();
        IntPtr pointer = Args.InBuffer.Read();
        IntPtr pointer2 = ComplexDataBuffer.Write();
        var data = new double[8192];
        Marshal.Copy(pointer, data, 0, 8192);
        for (int i = 0; i < 8192; i+=2)
        {
            data[i] = data[i];
            data[i + 1] = data[i] * Math.Cos(phaseCorrection) + data[i+1] * Math.Sin(phaseCorrection); 
        }
        Marshal.Copy(data, 0, pointer2, 8192);
       Args.SendOutputData = false;
       genericComplex1.SendData(ComplexDataBuffer);
    }

现在,这不起作用。原因是时间太长。我正在以每秒192000个样本的速度从声卡中采样音频。每当有4096个缓冲区可用时,上面的事件就会触发。因此,每20毫秒就有一个新的缓冲器到达。然后将该缓冲器发送到快速傅立叶变换例程,该例程生成信号强度与频率的关系图。虚数据实际上与实数据相同,但相位偏移了90度。在一个完美的世界里就是这样。然而,由于信号不平衡、不同的电子线路、不同的代码等原因,相位永远不会是90度。因此,需要一个校正因子,这就是方程的作用。现在,如果我更换

data[i] = data[i];
data[i + 1] = data[i] * Math.Cos(phaseCorrection) + data[i+1] * Math.Sin(phaseCorrection); 

带有

data[i] = data[i];
data[i+1] = data[i+1];

工作正常。
所以我需要指点。但这会更快吗?还是正弦和余弦函数会花太长时间?Cn我直接将数据发送到处理器(现在这变得非常不安全!)。

指针上的C#指针

您无法在安全上下文中直接访问非托管数据,因此需要将数据复制到托管容器:

using System.Runtime.InteropServices;
// ...
var data = new double[4096];
Marshal.Copy(pointer, data, 0, 4096);
// process data here

在我看来,这部分代码不需要unsafe上下文。

至于写回数据,实际上是完全一样的,但请注意参数顺序:

// finished processing, copying data back
Marshal.Copy(data, 0, pointer, 4096);

至于你上次关于绩效的笔记。正如我已经提到的,将var data = new double[8192];移动到data类成员,并在类构造函数中对其进行初始化,因此每次都不会进行分配(而且分配非常慢)。您可以在循环之外执行Math.Cos(phaseCorrection),因为phaseCorrection保持不变,当然Math.Sin(phaseCorrection)也是如此。类似这样的东西:

Marshal.Copy(pointer, this.data, 0, 8192);
var cosCache = Math.Cos(phaseCorrection);
var sinCache = Math.Sin(phaseCorrection);
for (int i = 0; i < 8192; i+=2)
{
    data[i] = data[i];
    data[i + 1] = data[i] * cosCache + data[i+1] * sinCache; 
}
Marshal.Copy(this.data, 0, pointer2, 8192);

所有这些都应该大大加快事情的发展。

如果你有一个IntPtr,你可以从中获得一个指针

    unsafe
    {
     IntPtr pointer =  Args.InBuffer.Read(); 
     // create a pointer to a double
     double* pd = (double*)pointer.ToPointer();
     // Now you can access *pd
     double firstDouble = *pd;
     pd++;  // moves to the next double in the memory block
     double secondDouble = *pd;
     // etc.
     }

现在,如果你想把数据放回数组中,它基本上是一样的:

double* pd = (double*)pointer.ToPointer();
*pd = 3.14;
++pd;
*pd = 42.424242;

您需要阅读并理解不安全代码和指针。对此要非常小心;你在这里编程没有安全网。