解组结果? [英] de-marshal results?
问题描述
这是对此
This is an extension to this question to be able to return an array rather than a scalar.
现在看起来可以通过matlab编码器从matlab代码中生成C代码了(请参见下文).我只是试图弄清楚如何使结果返回C#世界.这是我的第一次尝试:
The produced C code from the matlab code via matlab coder looks ok now (see below). I just try to figure out how to get the results back into the C# world. Here is my first attempt:
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:
考虑到大卫的回答,我目前正在尝试这样的事情:
Given David's answer I am trying something like this at the moment:
[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.
This only gives me one entry: 7 nCol and nRow are equal to 1.
推荐答案
您实际上是在问如何将emxArray_real_T
的内容读取到C#对象中.
You are essentially asking how to read the contents of a emxArray_real_T
into a C# object.
让我们首先考虑一维数组.像这样阅读:
Let's first consider a 1D array. Read it like this:
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
传递的数组,因此您可以使用它.
And you may not need to do the Marshal.Copy
step. You probably still have access to the array you passed for result.data
and so you can just use that.
二维情况几乎相同.再次,您需要检查result.numDimensions == 2
.
The two dimensional case is just more of the same. Again you'll want to check that 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到row-major的转换.
That puts the data in a one-dimensional array and presumably you'll want to put this into a two-dimensional managed array. Assuming the MATLAB is col-major, you'll need to deal with the col-major to row-major translation.
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++;
}
}
这篇关于解组结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!