这是此question的扩展,可以返回数组而不是标量。
通过matlab编码器从matlab代码生成的C代码现在看起来不错(见下文)。我只想弄清楚如何将结果带回C#世界。这是我的第一次尝试:
C#代码
[DllImport(@"C:\bla\CPlusPlus.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void test(ref emxArray_real_T a, ref emxArray_real_T result);
static void Main(string[] args)
{
double[,] array2D = new double[,] { { 1, 2, 4 }, { 1, 3, 4 } };
var wrapper = new EmxArrayRealTWrapper(array2D);
var t = wrapper.Value;
var t1 = wrapper.Value;
test(ref t, ref t1);
}
public class EmxArrayRealTWrapper : IDisposable
{
private readonly emxArray_real_T _value;
private GCHandle _dataHandle;
private GCHandle _sizeHandle;
public emxArray_real_T Value
{
get { return _value; }
}
public EmxArrayRealTWrapper(double[,] data)
{
_dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
_value.data = _dataHandle.AddrOfPinnedObject();
_sizeHandle = GCHandle.Alloc(new int[] { data.GetLength(0), data.GetLength(1) }, GCHandleType.Pinned);
_value.size = _sizeHandle.AddrOfPinnedObject();
_value.allocatedSize = data.GetLength(0) * data.GetLength(1);
_value.numDimensions = 2;
_value.canFreeData = false;
}
public void Dispose()
{
_dataHandle.Free();
_sizeHandle.Free();
GC.SuppressFinalize(this);
}
~EmxArrayRealTWrapper()
{
Dispose();
}
}
[StructLayout(LayoutKind.Sequential)]
public struct emxArray_real_T
{
public IntPtr data;
public IntPtr size;
public int allocatedSize;
public int numDimensions;
[MarshalAs(UnmanagedType.U1)]
public bool canFreeData;
}
Matlab代码:
function [result] = test(a, result)
%#codegen
if(~isempty(coder.target))
assert(isa(a,'double'));
assert(all(size(a) == [1 Inf]));
assert(isa(result,'double'));
assert(all(size(result) == [1 Inf]));
end
result = sum(a);
生成C代码
void test(const emxArray_real_T *a, emxArray_real_T *result)
{
real_T y;
int32_T k;
if (a->size[1] == 0) {
y = 0.0;
} else {
y = a->data[0];
for (k = 2; k <= a->size[1]; k++) {
y += a->data[k - 1];
}
}
k = result->size[0] * result->size[1];
result->size[0] = 1;
result->size[1] = 1;
emxEnsureCapacity((emxArray__common *)result, k, (int32_T)sizeof(real_T));
result->data[0] = y;
}
PS:
鉴于大卫的回答,我现在正在尝试这样的事情:
[DllImport(@"C:\bla\CPlusPlus.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void test(ref emxArray_real_T a, ref emxArray_real_T result);
static void Main(string[] args)
{
double[,] array2D = new double[,] { { 1, 2, 4 }, { 1, 3, 4 } };
double[,] temp = new double[,] { { 0 }, { 0 } };
var wrapper = new EmxArrayRealTWrapper(array2D);
var wrapper1 = new EmxArrayRealTWrapper(temp);
var t = wrapper.Value;
var t1 = wrapper1.Value;
test(ref t, ref t1);
// initialise this by your call to the native code
int[] size = new int[2];
Marshal.Copy(t1.size, size, 0, 2);
int nCol = size[0];
int nRow = size[1];
double[] data = new double[nCol * nRow];
Marshal.Copy(t1.data, data, 0, nCol * nRow);
}
这只给我一个条目:7 nCol和nRow等于1.
答案 0 :(得分:1)
您实际上是在询问如何将emxArray_real_T
的内容读入C#对象。
让我们首先考虑一维数组。读它是这样的:
emxArray_real_T result;
// initialise this by your call to the native code
int size = Marshal.ReadInt32(result.size);
double[] data = new double[size];
Marshal.Copy(result.data, data, 0, size);
就是这样。你想断言result.numDimensions == 1
。
您可能不需要执行Marshal.Copy
步骤。您可能仍然可以访问为result.data
传递的数组,因此您可以使用它。
二维情况更为相似。您再次想要检查result.numDimensions == 2
。
int[] size = new int[2];
Marshal.Copy(result.size, size, 0, 2);
int nCol = size[0];
int nRow = size[1];
double[] data = new double[nCol * nRow];
Marshal.Copy(result.data, data, 0, nCol * nRow);
这将数据放在一维数组中,大概你可能想把它放到一个二维托管数组中。假设MATLAB是col-major,你需要处理col-major到行主要翻译。
double[,] arr = new double[nRow, nCol];
int index = 0;
for (int col = 0; col<nCol; col++)
{
for (int row = 0; row<nRow; row++)
{
array[row, col] = data[index];
index++;
}
}