指针上的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我直接将数据发送到处理器(现在这变得非常不安全!)。
您无法在安全上下文中直接访问非托管数据,因此需要将数据复制到托管容器:
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;
您需要阅读并理解不安全代码和指针。对此要非常小心;你在这里编程没有安全网。