我从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中的一维数组。
在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移动它)一段时间(比如在调用非托管代码时)。
最后,您只是将地址用于内存块。确保这些块在调用期间不移动,并确保在两种编码语言中块的格式解释相同。
是eigenfrequencies / f数组和nrModes参数导致了麻烦。问题是100%的C面。呼叫/接收是好的。我刚刚在C函数Cr中处理了错误的本征频率,覆盖了东西。 Thnx和我一起思考。