如何将数组从.Net传递到C? [英] How do I pass an array from .Net to C?

查看:65
本文介绍了如何将数组从.Net传递到C?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用C语言编写的开源库 ,将其包装并将其暴露于.Net。

I am trying to make use of an open source library, written in C, by wrapping it and exposing it to .Net. I am not, by any stretch, a C expert.

到目前为止,我设法从F#调用了用C编写的演示代码。我设法通过遵循本指南,然后填写空白。我已经改编了C代码以期望将int传递给它,因此我至少可以将F#的标量值传入C。尽管没有返回值。

So far, I have managed to call the demo code, written in C, from F#. I managed to get this far by following this guide then filling in the blanks. I have adapted the C code to expect an int passed to it, so I can at least take in a scalar value from F# into C. No return value though.

但是

我的C代码是

extern "C"
{
    __declspec(dllexport) void DisplayHelloFromDLL(int i)
    {
        //printf("Hello from DLL !\n");
        cout << "You gave me ... an int: " << i << endl;

        // Load problem data
        c_float P_x[4] = { 4., 1., 1., 2., }; //covariance matrix
        c_int   P_nnz = 4; //number of non-zero elements in covar
        c_int   P_i[4] = { 0, 1, 0, 1, }; //row indices?
        c_int   P_p[3] = { 0, 2, 4}; //?
        c_float q[2] = { 1., 1., }; //linear terms
        c_float A_x[4] = { 1., 1., 1., 1., }; //constraint coefficients matrix
        c_int   A_nnz = 4; //number of non zero elements in constraints matrix
        c_int   A_i[4] = { 0, 1, 0, 2, }; //row indices?
        c_int   A_p[3] = { 0, 2, 4}; //?
        c_float l[3] = { 1., 0., 0., }; //lower bounds
        c_float u[3] = { 1., 0.7, 0.7, }; //upper bounds
        c_int n = 2; //number of variables (x)
        c_int m = 3; //number of constraints


        // Problem settings
        OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));

        // Structures
        OSQPWorkspace *work; // Workspace
        OSQPData *data;      // OSQPData

        // Populate data
        data = (OSQPData *)c_malloc(sizeof(OSQPData));
        data->n = n;
        data->m = m;
        data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
        data->q = q;
        data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
        data->l = l;
        data->u = u;


        // Define Solver settings as default
        osqp_set_default_settings(settings);

        // Setup workspace
        work = osqp_setup(data, settings);

        // Solve Problem
        osqp_solve(work);

        // Clean workspace
        osqp_cleanup(work);
        c_free(data->A);
        c_free(data->P);
        c_free(data);
        c_free(settings);
    }
}

而我的C#代码是

class Program
    {
        [DllImport("TestLibCpp.dll")]
        public static extern void DisplayHelloFromDLL(int i);
        static void Main(string[] args)
        {
            Console.WriteLine("This is F# program");
            DisplayHelloFromDLL(52);
        }
    }

要缩小此问题的重点:该怎么办我将P_x设置为参数,以便从F#中传递?

To keep the focus of this question narrow: how do I make P_x a parameter, to be passed in from F#?

推荐答案

阅读AlexF的链接并开始工作后,我认为我会在这里为有类似问题的任何人发布答案。
我可能会弄错一些概念,但是代码可以正常工作。如果我弄错了任何细节,请让我知道,我将进行编辑。

After reading AlexF's link and getting something to work, I thought I'd post an answer here for anyone with a similar problem. I may get some of the concepts wrong, but the code works. If I get any details wrong, let me know and I will edit.

要注意的概念:
可拆分类型:这些类型具有相同的.Net(托管)和C(非托管)的内部表示形式。可调度类型由封送拆收器固定,这似乎意味着将指针从.Net传递到C,而不是复制值。 Blittable类型的内存位置被锁定,直到返回非托管函数为止。不确定这将如何影响垃圾回收。

Concepts to be aware of: Blittable types: These are types that have the same internal representation in .Net (managed) and in C (unmanaged). Blittable types are 'pinned' by the marshaler which seems to mean that a pointer is passed from .Net to C, rather than the values being copied. The memory location of the Blittable type is locked until the unmanaged function returns. Not sure how this affects garbage collection.

输入/输出属性:Blittable数组作为In参数传递。如果要使用它们作为返回值,则必须将它们明确标记为 Out。

In/Out attributes: Blittable arrays are passed as In paramters. You must explicitly mark them as Out if you wish to use them as a return value.

无论如何,这是有效的代码。

Anyway, here is the code that works.

不受管理:

extern "C"
{
    __declspec(dllexport) void DisplayHelloFromDLL(c_float* P_x)
    {
        //printf("Hello from DLL !\n");
        //cout << "You gave me ... an int: " << i << endl;

        // Load problem data
        //c_float P_x[4] = { 4., 1., 1., 2., }; //covariance matrix
        c_int   P_nnz = 4; //number of non-zero elements in covar
        c_int   P_i[4] = { 0, 1, 0, 1, }; //row indices?
        c_int   P_p[3] = { 0, 2, 4}; //?
        c_float q[2] = { 1., 1., }; //linear terms
        c_float A_x[4] = { 1., 1., 1., 1., }; //constraint coefficients matrix
        c_int   A_nnz = 4; //number of non zero elements in constraints matrix
        c_int   A_i[4] = { 0, 1, 0, 2, }; //row indices?
        c_int   A_p[3] = { 0, 2, 4}; //?
        c_float l[3] = { 1., 0., 0., }; //lower bounds
        c_float u[3] = { 1., 0.7, 0.7, }; //upper bounds
        c_int n = 2; //number of variables (x)
        c_int m = 3; //number of constraints


        // Problem settings
        OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));

        // Structures
        OSQPWorkspace *work; // Workspace
        OSQPData *data;      // OSQPData

        // Populate data
        data = (OSQPData *)c_malloc(sizeof(OSQPData));
        data->n = n;
        data->m = m;
        data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
        data->q = q;
        data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
        data->l = l;
        data->u = u;


        // Define Solver settings as default
        osqp_set_default_settings(settings);

        // Setup workspace
        work = osqp_setup(data, settings);

        // Solve Problem
        osqp_solve(work);

        // Clean workspace
        osqp_cleanup(work);
        c_free(data->A);
        c_free(data->P);
        c_free(data);
        c_free(settings);
    }
}

托管(F#)

open System.Runtime.InteropServices

module ExternalFunctions =
    [<DllImport("TestLibCpp.dll")>]
    extern void DisplayHelloFromDLL(float[] i)

[<EntryPoint>]
let main argv = 
    let P_x = [|4.; 1.; 1.; 2.|]
    ExternalFunctions.DisplayHelloFromDLL(P_x);
    0 // return an integer exit code

这篇关于如何将数组从.Net传递到C?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆