Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#将结构数组复制到双精度数组_C#_Memcpy_Value Type - Fatal编程技术网

C#将结构数组复制到双精度数组

C#将结构数组复制到双精度数组,c#,memcpy,value-type,C#,Memcpy,Value Type,如何将演示数组复制到doubles数组中,而不必通过每个元素执行for(…)?在C++中,我使用MeMCPY,但是在C语言中,我没有找到元帅中需要的东西。 [StructLayout(LayoutKind.Sequential)] public struct Demo { double X; double Y; } var data = new Demo[128]; FillWithMeaningfulValues(data); double[] doubles; Co

如何将演示数组复制到doubles数组中,而不必通过每个元素执行for(…)?在C++中,我使用MeMCPY,但是在C语言中,我没有找到元帅中需要的东西。
[StructLayout(LayoutKind.Sequential)]
public struct Demo
{
    double X;
    double Y;
}


var data = new Demo[128];

FillWithMeaningfulValues(data);

double[] doubles;

Copy(data, out doubles); // ?
void方法不想使用(Demo[]Demo,out double[]double)
{
双精度=新双精度[demo.Length*2];
对于(int i=0,j=0;i
您可以这样做
Marshal.Copy
do提供您所需的内容

void MethodIDoNotWantToUse(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    for(int i = 0, j = 0; i < demo.Length; ++i)
    {
        doubles[j++] = demo[i].X;
        doubles[j++] = demo[i].Y;
    }  
}

void MethodIWouldPreferToUse(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    memcopy(doubles, demo, demo.Length * 2 * sizeof(double));
}

由于结构是可blittable的,因此结构的数组是可blittable的。因此,您可以使用
marshall.copy
将struct的数组固定并复制到双数组中

Demo[] array = new Demo[2];
array[0] = new Demo {X = 5.6, Y= 6.6};
array[1] = new Demo {X = 7.6, Y = 8.6};
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
try
{
    IntPtr pointer = handle.AddrOfPinnedObject();
    double[] copy = new double[array.Length*2];//This length may be calculated
    Marshal.Copy(pointer, copy, 0, copy.Length);
}
finally
{
    if (handle.IsAllocated)
        handle.Free();
}

您最好将其与希望避免的更简单的
for
循环进行基准测试。
for
循环可以完美地执行。

可以编写一个通用方法来转换任何兼容类型的数组(所谓“兼容”,我的意思是“元素必须是值类型,并且元素的大小必须兼容”)

可以使用p/Invoke调用Windows API CopyMemory()方法

但是,请记住,这样做可能没有任何性能优势;你应该仔细地计时以确定时间

void CopyDemoArrayToDoubleArray(Demo[] demo, out double[] doubles)
{
    doubles = new double[demo.Length * 2];
    GCHandle gch = GCHandle.Alloc(demo, GCHandleType.Pinned);
    try
    {
        IntPtr demoPtr = gch.AddrOfPinnedObject();
        Marshal.Copy(demoPtr, doubles, 0, doubles.Length);
    }
    finally
    {
        gch.Free();
    }
}
[DllImport(“kernel32.dll”,EntryPoint=“CopyMemory”,SetLastError=false)]
公共静态外部无效CopyMemory(IntPtr dest、IntPtr src、uint count);
公共TOut[]转换数组(TIn[]输入),其中TIn:struct其中TOut:struct
{
如果(输入==null)
抛出新的ArgumentNullException(“输入”);
int sizeTIn=Marshal.SizeOf(typeof(TIn));
int-sizeTOut=Marshal.SizeOf(typeof(TOut));
int-sizeBytes=input.Length*sizeTIn;
如果((sizeBytes%sizeTOut)!=0)
抛出新ArgumentException(“输入类型的大小与输出类型的大小不兼容”);
int sizeOut=sizeBytes/sizeOut;
var输出=新TOut[sizeOut];
GCHandle inHandle=GCHandle.Alloc(输入,GCHandleType.pinted);
GCHandle outHandle=GCHandle.Alloc(输出,GCHandleType.pinted);
尝试
{
IntPtr inPtr=inHandle.addrofPindedObject();
IntPtr outPtr=outHandle.AddrOfPinnedObject();
CopyMemory(输出端、输入端(uint)大小字节);
}
最后
{
outHandle.Free();
inHandle.Free();
}
返回输出;
}
例如,您可以这样称呼它:

[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);

public TOut[] ConvertArray<TIn, TOut>(TIn[] input) where TIn:struct where TOut:struct
{
    if (input == null)
        throw new ArgumentNullException("input");

    int sizeTIn   = Marshal.SizeOf(typeof(TIn));
    int sizeTOut  = Marshal.SizeOf(typeof(TOut));
    int sizeBytes = input.Length*sizeTIn;

    if ((sizeBytes % sizeTOut) != 0)
        throw new ArgumentException("Size of input type is not compatible with size of output type.");

    int sizeOut = sizeBytes/sizeTOut;

    var output = new TOut[sizeOut];

    GCHandle inHandle  = GCHandle.Alloc(input,  GCHandleType.Pinned);
    GCHandle outHandle = GCHandle.Alloc(output, GCHandleType.Pinned);

    try
    {
        IntPtr inPtr  = inHandle.AddrOfPinnedObject();
        IntPtr outPtr = outHandle.AddrOfPinnedObject();

        CopyMemory(outPtr, inPtr, (uint)sizeBytes);
    }

    finally
    {
        outHandle.Free();
        inHandle.Free();
    }

    return output;
}
Demo[]测试=新的Demo[10];
对于(int i=0;i<10;++i)
测试[i]=新演示{X=i,Y=i};
var结果=转换阵列(测试);
对于(int i=0;i<20;++i)
Console.WriteLine(结果[i]);

您可以使用简单的LINQ查询来获得结果:
double[]doubles=data.SelectMany(d=>new[]{d.X,d.Y}).ToArray()@UlugbekUmirov仍然会一个接一个地遍历它们。他试图一次复制整个块。@TimGoodman你是对的,但如果只有128个元素,我看不到大容量复制的性能优势。这只是一个例子。我的真实数据将更大(也更复杂的结构,但仍然只由可blittable类型组成)。我之所以问,是因为我知道C++的方式,却不知道C的方法来实现高效的拷贝。然而,你是对的,在许多情况下,你在评论中的解决方案将是一个完全可行的答案。是的。我使用这种技术在内存中随机播放音频+1.
Demo[] test = new Demo[10];

for (int i = 0; i < 10; ++i)
    test[i] = new Demo {X = i, Y = i};

var result = ConvertArray<Demo, double>(test);

for (int i = 0; i < 20; ++i)
    Console.WriteLine(result[i]);