gpt4 book ai didi

c# - 在 C# 中读写 C++ 动态数组 (InteropServices)

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:19:52 25 4
gpt4 key购买 nike

我有一个 C++ 类,它有一个标题(matrixheader.h)这样:

#pragma once

class M
{
public:
M(int m,int n);
void MSet(int m,int n,double d);
double MGet(int m,int n);
~M();
private:
double** mat;
};

类在(matrixbody.cpp)中定义如下:它是在Win32平台上构建的。

#pragma once
#include "matrixhead.h"

M::M(int m,int n)
{
mat = new double*[m];
for (int i = 0; i < m; i++)
{
mat[i] = new double[n];
}
}

void M::MSet(int m,int n,double d)
{
mat[m][n] = d;
}

double M::MGet(int m,int n)
{
double d = mat[m][n];
return d;
}

M::~M()
{
delete[] mat;
}

我已经为类做了一个包装器(matrixwrapper.cpp):包装器也是在 Win32 平台中构建的。

#include "matrixhead.h"
#include "matrixbody.cpp"

extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M o(m,n);
return &o;
}

extern "C" __declspec(dllexport) void setData(void* mp,int m,int n,double d)
{
M* ap = (M*)mp;
M a = *ap;
a.MSet(m,n,d);
}

extern "C" __declspec(dllexport) double getData(void* mp,int m,int n)
{
M* bp = (M*)mp;
M b = *bp;
double d = b.MGet(m,n);
return d;
}

我将类导入到 C# 并尝试从 C# 调用 C++ dl 方法:

using System;
using System.Runtime.InteropServices;


namespace wrappertest
{
class Program
{
[DllImport("matrixwrapper.dll")]
unsafe public static extern void* Make(int m,int n);

[DllImport("matrixwrapper.dll")]
unsafe public static extern void setData(void* mp,int m, int n,double d);

[DllImport("matrixwrapper.dll")]
unsafe public static extern double getData(void* mp,int m, int n);

static unsafe void Main(string[] args)
{
void* p = Make(10, 10);
setData(p,10,1,10);
Console.WriteLine(getData(p,10,1));
}
}
}

但是当我尝试从 C# 运行 C++ dll 方法时,出现以下错误

1//试图读取或写入 protected 内存。这通常表示在 x64 中运行 C# 代码时其他内存已损坏。

2//在x86 Active/x86或AnyCPU平台上运行时,试图加载格式不正确的程序。

问题:

1//上面的代码有什么问题?

2//考虑到我的最终目标是在 C++ 中创建一个 2d 动态数组并在数组中读取/写入数据,例如上面 matrixheader.h 文件中的一个 double**mat 从 C# 中?还有其他的吗实现方式?

最佳答案

让我们先从简单的事情开始:

An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.

这仅表示您的平台不匹配。您要么尝试在 x64 .NET 运行时加载 x86 C++ dll,要么相反。

下面的错误才是真正的问题:

Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.

这是意料之中的,因为您的 Make 函数在堆栈上创建一个对象,然后返回指向它的指针。当您读回此对象时,堆栈上的内容已更改(堆栈正在被重用),并且 mat 指针指向其他地方,很可能指向未分配的内存。

see this answer我在其中更深入地了解了这个问题(它是 C#,但它是同一个问题)。

你必须分配一些动态内存来解决你的问题。你可以试试:

extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M* o = new M(m,n);
return o;
}

当然,如果您不想泄漏内存,则必须再创建一个方法来执行匹配的delete

此外,正如 Mgetz 在评论中指出的那样,M 类本身存在内存泄漏。析构函数中的 delete[] mat; 调用不会释放每个已分配的内存块。您在构造函数中调用 new m + 1 次,这意味着您必须调用 delete[] m + 1 次也在析构函数中,每个 new 一次。您可能应该将 mn 保留为您的类中的字段(至少 m 是强制性的,以了解对 delete[ 的调用次数] 你必须做的)。

更好的解决方案是使用单个数组而不是交错数组。您将该数组中的索引 i, j 计算为 i * m + j。您也可以使用 std::vector 或完全在 C# 中完成:

public class M
{
private double[] _items;
private int _m;
private int _n;

public M(int m, int n)
{
_items = new double[m * n];
_m = m;
_n = n;
}

public this[int i, int j]
{
// Here, you should perform a bounds check on i and j against _m and _n
get { return _items[i * _m + j]; }
set { _items[i * _m + j] = value; }
}
}

关于c# - 在 C# 中读写 C++ 动态数组 (InteropServices),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27963825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com