如何将 C# 中的二维数组传递给C++ DLL?

How to pass a two-dimensional array in C# to a C++ DLL?

本文关键字:C++ DLL 二维数组      更新时间:2023-10-16

我想将 C# 中的二维数组作为参数传递给 DLL C++函数(当我使用 CUDA C++ 时必须C++(。我尝试了很多东西,但未能直接使用数组或向量传递它。我唯一能做的就是将其转换为一维数组,将其与其维度一起传递给函数,然后将其转换回二维向量。 下面是C++ DLL 代码:

int Add(int* a, int m, int n)
{
int i, j, ans;
vector<vector<int>> A(m, vector<int>(n));
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
A[i][j] = a[i * n + j];
// Main calculations
return ans;
}

这是传递数组的 C# 代码:

[DllImport("CUDALib.dll")]
static extern int Add(int[] a, int m, int n);
private void PassArray(int[,] A)
{
int i, j, m, n, ans;
int[] a;
m = A.GetLength(0);
n = A.GetLength(1);
a = new int[m * n];
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
a[i * n + j] = A[i, j];
ans = Add(a, m, n);
}

我有没有更快,更有效,更直接的方法可以做到这一点吗?

C# 中的 2D 数组在内存中是连续的,因此不需要在两端复制所有这些内存。应按原样在 C# 中传递数组指针:

[DllImport("CUDALib.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int Add(int[,] a, int m, int n);
static void PassArray(int[,] A)
{
int m = A.GetLength(0);
int n = A.GetLength(1);
int ans = Add(A, m, n);
}

然后访问C++中的各个元素,如下所示:

extern "C" __declspec(dllexport) int Add(int* a, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d %d: %dn", i, j, a[i * n + j]);
// Main calculations
return 0;
}

您可以使用类来封装指针、行和列,然后访问 传递一维数组,就好像它是标准二维数组一样。无需在函数中创建本地副本,因为 p 在调用中仍然有效。@mnistic的回答还指出,没有必要在 C# 中制作 1D 副本。

class Array2D {
public:
Array2D(int* p, size_t rows, size_t cols) : p(p), cols(cols), rows(rows){};
int* operator[](int row) { return p + row * cols; }
const size_t rows;  // not needed but can be used for adding boundary checks
const size_t cols;
private:
int *const p;
};

返回表示为 2D 数组的数组元素的总和

extern "C" __declspec(dllexport) int Add(int* p, int rows, int cols)
{
Array2D a(p, rows, cols);
int sum{};
for (int i = 0; i < rows; ++i)
for (int ii = 0; ii < cols; ++ii)
sum += a[i][ii];
return sum;
}

这是一个测试,显示了它是如何工作的

int main()
{
int* p = new int[6]{ 1, 2, 3, 4, 5, 6 };
Array2D a2d(p, 3, 2);   // three rows, two cols
std::cout << a2d[0][0] << 'n';  // prints 1
std::cout << a2d[1][1] << 'n';  // prints 4
a2d[1][1] = 10;
std::cout << a2d[1][1] << 'n';  // now prints 10
std::cout << a2d[2][0] << 'n';  // prints 5
std::cout << a2d[2][1] << 'n';  // prints 6
}

以下是阿卜杜勒·阿齐兹回答的模板类:

template <class TdataType> 
class Array2d {
public:
Array2d<TdataType>(TdataType* arr, size_t rows, size_t cols) : p(arr), cols(cols), rows(rows) {};
TdataType* operator[](int row) { return p + row * cols; }
const size_t rows;  // not needed but can be used for adding boundary checks
const size_t cols;
private:
TdataType* const p;
};

下面是使用它的示例:

auto my2dArray = Array2d<uint8_t>(inputArrayFromCsharp, numRows, numCols);