从C#调用C:当其他人如此顺利时,如何编组一个二维2D数组?

问题描述 投票:0回答:2

我从C#调用一个C例程,有一些双精度,整数,一个大字符串和一些数组作为参数。一些数组正确返回,使用正确的值,只有一个数组不返回。数组在返回C#时损坏,而不是在执行C例程期间。

C# - 侧:

[DllImport(@"Critias.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Cr", 
            CharSet = CharSet.Ansi, BestFitMapping =false,ThrowOnUnmappableChar =true)]
public static extern int Cr([In] StringBuilder isc, 
            int nrModes, 
            double[] eigenfrequencies, 
            ref double error, 
            double[,] defl,
            double[] reactions,
            double[,] force);

public double[,] Deflection;
public double[,] MemberEndforces;       
public double[] Reactions;
public double error;

    ....

var eigenFreq = new double[nrModes + 1]; // +1 for C-sides pseudo FORTRAN arrays
MemberEndforces = new double[mbCount,12];                
Deflection = new double[mbCount + 1,6];               
Reactions = new double[6];       
info = NativeMethods.Cr(
            isc, nrModes, eigenFreq, ref error,  Deflection, Reactions, MemberEndforces);

现在,除了MemberEndforces之外,所有参数都可以回来。此外,当我在调用者和被调用者端交换Reactions和MemberEndforces的顺序时,Reactions从Cr OK返回,但不是MemberEndforces。我在VS Watch面板中为MemberEndforces获取“无法读取内存”。另外,如果我不填写MemberEndforces C-side,那么就什么也不做,它没有任何区别:仍然是相同的错误消息

和C面:

extern "C"
{
    __declspec(dllexport) int __cdecl Cr(
        char *_isc,
        int nM_calc,
        double* f,
        double* error,
        double* deflection,     
        double* reactions ,
        double* endforces ) // this is the annoying one
     {
      double** Q; // malloc-ed somewhere.
      double* D;
      double *R;

     .....
     for (int ii = 0; ii < DoF; ii++)
            deflection[ii ] = D[ii+1];
    for (int ii = 0; ii < nE; ii++)
        for (int jj = 0; jj < 12; jj++)
        {
            endforces[ii * 12 + jj] = Q[ii+1][jj + 1];// values OK,but...
        }
    for (int ii = 0; ii < 6; ii++)
        reactions[ii] = R[ii+1];

            ......

        }

当然,问题是:我做错了什么(为什么,也许?)?

c# c marshalling
2个回答
1
投票

这里似乎有一些概念问题。至于为什么最后一个参数可能被破坏。您将其定义为二维数组(c#),然后将其用作C中的一维数组。

在C中,数组是指向某个特定类型的内存块的指针(示例为double)。通常,您将其分配为* typeof(double)* arraysize *。二维数组是指向某种类型指针的内存块的指针。要创建2D数组,您必须首先分配指针数组,然后将每个指针设置为数组。你可能会看到这样的东西:Multidimensional array initialization in C

C#在这里有不同的选项,请参阅:What are the differences between a multidimensional array and an array of arrays in C#? Plus,C#是一个托管内存系统,所以将指针从C#(比如C)中传出是一个问题,因为GC(垃圾收集器)可能随时启动并更改内存变量的地址(从C运行C代码下拉出地毯)。 C#有一种修复内存的方法(使用'unsafe'代码),它允许你“锁定”和解决(阻止GC移动它)一段时间(比如在调用非托管代码时)。

最后,您只是将地址用于内存块。确保这些块在调用期间不移动,并确保在两种编码语言中块的格式解释相同。


0
投票

是eigenfrequencies / f数组和nrModes参数导致了麻烦。问题是100%的C面。呼叫/接收是好的。我刚刚在C函数Cr中处理了错误的本征频率,覆盖了东西。 Thnx和我一起思考。

© www.soinside.com 2019 - 2024. All rights reserved.