c# 包装到本机 c++代码,包装一个参数,该参数是指向数组的指针

发布于 2024-08-30 16:09:40 字数 1073 浏览 11 评论 0原文

我有以下简单的 C++ 非托管代码 DLL;

extern "C" __declspec(dllexport) void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length); 

void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length) 
{
    for (int i = 0 ; i < length ; length++)
    {
        for (int j = 0; j < 3; j++)
        { 
            pointerArray[i][j] = pointerArray[i][j] * scalar;
        }
    }
}

我尝试在 c# 中为上述内容编写以下包装函数:

    [DllImport("sample.dll")]
public static extern void ArrayMultiplier(ref float elements, int scalar, int length);

其中 elements 是一个 2 维 3x3 数组:

public float[][] elements = 
        {
            new float[]  {2,5,3},
            new float []  {4,8,6},
            new float []  {5,28,3}
        };

上面给出的代码可以编译,但是当调用包装函数时程序崩溃:

Wrapper.ArrayMultiplier(ref elements, scalar, length);

请在这里帮助我,并告诉我出了什么问题使用上面的代码,或者如何为简单的 C++ 函数编写包装器:

void SimpleFunction(float (*pointerToArray)[3]);

提前谢谢大家

I have the following simple DLL in c++ un-managed code;

extern "C" __declspec(dllexport) void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length); 

void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length) 
{
    for (int i = 0 ; i < length ; length++)
    {
        for (int j = 0; j < 3; j++)
        { 
            pointerArray[i][j] = pointerArray[i][j] * scalar;
        }
    }
}

I have tried writing the following wrapper function for the above in c#:

    [DllImport("sample.dll")]
public static extern void ArrayMultiplier(ref float elements, int scalar, int length);

where elements is a 2 dimentional 3x3 array:

public float[][] elements = 
        {
            new float[]  {2,5,3},
            new float []  {4,8,6},
            new float []  {5,28,3}
        };

The code given above compiles, but the program crashes when the wrapper function is called:

Wrapper.ArrayMultiplier(ref elements, scalar, length);

Please help me here, and tell me whats wrong with the code above, or how a wrapper can be written for a simple c++ function:

void SimpleFunction(float (*pointerToArray)[3]);

Thank you all in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小巷里的女流氓 2024-09-06 16:09:40

有几种方法可以做到这一点。

不安全的路线,适用于二维数组(您拥有的):

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL(int inPtr, int outPtr, int inSize1, int size2, int param);

通过调用

    private unsafe float[] MyFunc(float[] inData, int inSize1, int inSize2, int param1, int param2) {
        float[] theOutData = new float[inChannelData.Length];
        fixed (float* inBufferPtr = &inChannelData[0]) {
            fixed (float* outBufferPtr = &theOutData[0]) {
                MyFuncViaDLL((int)inBufferPtr, (int)outBufferPtr, inSize1, inSize2, param);
            }
        }
        return theOutData;
    }

这将以不安全的方式工作,但您需要将输入数组更改为一维数组。无论如何,我认为这是一个更好的主意,但这只是我的想法。

如果您想保证安全,请添加另一个参数,即数组本身的大小,然后进行一些编组。不过,您再次需要进入一维数组:

相反,您想要进行一些编组,如下所示:

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL([MarshalAs(UnmanagedType.LPArray)]float[] inPtr, int size1, int size2, int totalSize, int param2);

然后直接调用该函数:

    MyFuncViaDLL(array, size1, size2, size1*size2, param1, param2);

然后您的 C++ 将更改为:

void ArrayMultiplier(float *pointerArray, int inSize1, int inSize2, int inTotalSize, int scalar) 
{
    int i, j, index;
    for (i = 0 ; i < size1; i++)//note that length++ would be very very wrong here
    {
        for (j = 0; j < size2; j++)
        { 
            index = i*size2 + j;
            if(index >= inTotalSize) { return; } //avoid walking off the end
            pointerArray[i*size2 +  j] *= scalar;
        }
    }
}

如果需要,您可以添加检查反对总长度,以确保您不会走到最后,但这将是一个相当大的速度打击(足以不想使用 C++),就好像语句不是免费的一样。

然而,完成所有这些之后,我不得不问 - 为什么不直接在 C# 中执行此操作,并省去编组等互操作服务的麻烦?对于复杂的事情,C++ 往往更快,但对于快速数组遍历,我发现 C# 表现得相当好。一旦它是一维数组,在 C# 中也可以很快:

 int i;
 for (i = 0; i < array.length; i++){
    array[i] *= scalar;
 }

There are a few ways to do this.

The unsafe route, which works well with 2D arrays (that you have):

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL(int inPtr, int outPtr, int inSize1, int size2, int param);

called via

    private unsafe float[] MyFunc(float[] inData, int inSize1, int inSize2, int param1, int param2) {
        float[] theOutData = new float[inChannelData.Length];
        fixed (float* inBufferPtr = &inChannelData[0]) {
            fixed (float* outBufferPtr = &theOutData[0]) {
                MyFuncViaDLL((int)inBufferPtr, (int)outBufferPtr, inSize1, inSize2, param);
            }
        }
        return theOutData;
    }

That will work in an unsafe way, but you'd need to change your input arrays into 1D arrays. I think that's a better idea anyway, but that's just the way that I think.

If you want to be safe about it, add another parameter that is the size of the array itself, and then do some marshalling. Again, though, you'll need to go into 1D arrays:

Instead, you want to do some marshalling, like so:

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL([MarshalAs(UnmanagedType.LPArray)]float[] inPtr, int size1, int size2, int totalSize, int param2);

Then just call the function directly:

    MyFuncViaDLL(array, size1, size2, size1*size2, param1, param2);

Your C++ would then change to:

void ArrayMultiplier(float *pointerArray, int inSize1, int inSize2, int inTotalSize, int scalar) 
{
    int i, j, index;
    for (i = 0 ; i < size1; i++)//note that length++ would be very very wrong here
    {
        for (j = 0; j < size2; j++)
        { 
            index = i*size2 + j;
            if(index >= inTotalSize) { return; } //avoid walking off the end
            pointerArray[i*size2 +  j] *= scalar;
        }
    }
}

If you want, you can add in the check against total length to ensure that you don't walk off the end, but that'll be a pretty big speed hit (enough to want to not use C++), as if statements aren't free.

Having done all of that, however, I have to ask-- why not just do this directly in C#, and save yourself the hassle of interop services like marshalling? C++ tends to be faster for complicated things, but for a quick array walk, I've seen C# behave pretty well. It can be pretty quick in C# too, once it's a 1D array:

 int i;
 for (i = 0; i < array.length; i++){
    array[i] *= scalar;
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文