此问题是此question的扩展。
我想为二维情况调整包装。这是我的第一次尝试:
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) * sizeof(double);
_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;
}
PS:
原始的matlab代码如下所示:
function [x] = test(a)
%#codegen
x = 0;
if(~isempty(coder.target))
assert(isa(a,'double'));
assert(all(size(a) == [1 Inf]));
end
x = sum(a);
,可以像这样调用:
a = [ 1 2; 3 4]
r = test(a)
制造
r =
4 6
不幸的是,生成的C无法实现Matlab可以实现的目标(即返回数组):
__declspec(dllexport) real_T test(const emxArray_real_T *a);
real_T test(const emxArray_real_T *a)
{
real_T x;
int32_T k;
if (a->size[1] == 0) {
x = 0.0;
} else {
x = a->data[0];
for (k = 2; k <= a->size[1]; k++) {
x += a->data[k - 1];
}
}
return x;
}
答案 0 :(得分:2)
我假设MATLAB数组结构使用col-major排序。在这种情况下,struct构造函数需要如下所示:
public EmxArrayRealTWrapper(double[,] data)
{
int nRow = data.GetLength(0);
int nCol = data.GetLength(1);
double[] flattenedData = new double[nCol * nRow];
int index = 0;
for (int col=0; col<nCol; col++)
{
for (int row=0; row<nRow; row++)
{
flattenedData[index] = data[row, col];
index++;
}
}
_dataHandle = GCHandle.Alloc(flattenedData, GCHandleType.Pinned);
_value.data = _dataHandle.AddrOfPinnedObject();
_sizeHandle = GCHandle.Alloc(new int[] { nCol, nRow }, GCHandleType.Pinned);
_value.size = _sizeHandle.AddrOfPinnedObject();
_value.allocatedSize = nCol * nRow;
_value.numDimensions = 2;
_value.canFreeData = false;
}
如果本机代码需要row-major,那么它就更简单了。 C#多维数组存储为连续的行主数组。因此,您可以使用与我最近提出的问题中提供的一维代码非常相似的代码。
public EmxArrayRealTWrapper(double[,] data)
{
int nRow = data.GetLength(0);
int nCol = data.GetLength(1);
_dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
_value.data = _dataHandle.AddrOfPinnedObject();
_sizeHandle = GCHandle.Alloc(new int[] { nRow, nCol }, GCHandleType.Pinned);
_value.size = _sizeHandle.AddrOfPinnedObject();
_value.allocatedSize = nCol * nRow;
_value.numDimensions = 2;
_value.canFreeData = false;
}
请注意,这两种变体在将数据传递给本机代码的方式上有所不同。第一个版本传递原始数据的副本。第二个传递对原始数据的引用。我不确定您希望代码如何表现。很容易调整第二个版本来传递副本。至于第一个版本,如果您希望本机代码修改数据并将这些修改反映回托管代码,那么您需要在返回本机调用后重新编组修改。