代码之家  ›  专栏  ›  技术社区  ›  Chechy Levas

如何将数组从.NET传递到C?

  •  1
  • Chechy Levas  · 技术社区  · 6 年前

    我想利用 open source library, written in C 将其包装并暴露在.NET中。无论如何,我不是C专家。

    到目前为止,我已经设法从F_调用了用C编写的演示代码。我通过跟踪 this guide 然后填空。我对C代码进行了调整,以期望传递给它一个int,因此我至少可以将一个标量值从f传入C。但是没有返回值。

    但是使用数组要复杂得多。

    我的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);
        }
    }
    

    我的密码是

    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_传入的参数?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Robert Harvey    6 年前

    在阅读了Alexf的链接并开始工作之后,我想我会在这里为有类似问题的人发布一个答案。 我可能误解了一些概念,但代码是有效的。如果我有任何错误的细节,请告诉我,我会编辑。

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

    输入/输出属性:可闪电数组作为输入参数传递。如果希望将它们用作返回值,则必须将它们显式标记为out。

    不管怎样,这是有效的代码。

    非托管:

    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